Linux
未读重定向
相关好文 | CSDN
1. 什么是重定向?重定向本质上就是操作文件描述符(每一个打开的文件或设备在内核中都有一个编号,称为文件描述符),即 修改标准输入/输出/错误 这三个文件描述符(file descriptor,简称 FD)的指向,让它们 不再指向默认终端(屏幕、键盘),而是指向 文件、设备或者其他地方。
文件描述符编号
描述
默认指向
0
标准输入 stdin
键盘
1
标准输出 stdout
屏幕
2
标准错误 stderr
屏幕
比如常见的 shell 命令:
1ls > output.txt
背后的本质动作是:
关闭文件描述符 1(stdout)
打开或创建 output.txt
将描述符 1 指向 output.txt 文件
这样,所有本应该显示在屏幕上的内容,都会写入 output.txt 文件。
2. 常见的重定向符号
符号
含义
功能描述
示例
效果
>
输出重定向(覆盖),stdout
把标准输出写入到指定文件,若文件存在则 清空 后写入,否则创建
ls > out.tx ...
Linux
未读基础 IO —— C 语言文件 I/O 操作基础
前言1. 文件的基本概念
文件的定义:
文件 = 内容(数据) + 属性(如权限、修改时间、所有者等)。
属性是文件管理的重要依据,贯穿文件的存储、访问和控制全流程。
2. 文件的两种状态
打开的文件
触发条件:由进程主动打开(如读写操作)。
存储位置:加载到内存中。
核心机制:
进程关联:每个打开的文件需与进程绑定,形成“进程-文件”的 多对一关系(1: n 关系:一个进程可打开多个文件)。
内核管理:操作系统为每个打开的文件创建 文件打开对象(如 struct XXX),记录文件属性、状态及链表指针(如 next),便于统一管理。
未打开的文件
存储位置:磁盘上。
核心问题:如何高效组织海量未打开文件,支持 快速增删查改。
管理目标:通过目录结构、文件系统层级等实现文件分类与定位。
3. 操作系统如何管理打开的文件
管理原则 —— 先描述,后组织:
描述:为每个打开的文件创建内核对象(如 struct file),记录文件属性(如读写位置、权限)和操作接口。
组织:通过链表、哈希 ...
Linux
未读fork + exec 系列函数创建子进程并执行其他程序(跨语言衔接示例)
CSDN 相关文章 fork(2) - Linux 手册页 exec(3) - Linux 手册页
在 Linux 系统编程中,fork() 和 exec() 是进程控制的两大核心。本文将演示如何使用 fork 创建子进程,再使用 exec 执行外部程序,展示多语言之间的 协同执行 过程。
1. fork + exec 基础原理
fork():复制当前进程,返回两次(一次给父进程,一次给子进程)
exec*():用新程序 替换当前进程映像(进程 ID 不变)
通常模式:
12345678910pid_t pid = fork();if (pid == 0) // 子进程执行新程序{ execl("/bin/ls", "ls", "-l", NULL); perror("execl"); // 出错处理 ...
Linux
未读从零到一实现一个简易 Shell这应该是个蛮有趣的话题:“什么是 Shell”?相信只要摸过计算机,对于操作系统(不论是 Linux、Unix 或者是 Windows)有点概念的朋友们大多听过这个名词,因为只要有“操作系统“那么就离不开 Shell 这个东西。不过,在讨论 Shell 之前,我们先来了解一下计算机的运行状况吧!举个例子来说:当你要计算机传输出来“音乐”的时候,你的计算机需要什么东西呢?
硬件:当然就是需要你的硬件有“声卡芯片”这个配备,否则怎么会有声音;
核心管理:操作系统的核心可以支持这个芯片组,当然还需要提供芯片的驱动程序啰;
应用程序:需要使用者(就是你)输入发生声音的指令啰!
这就是基本的一个输出声音所需要的步骤!也就是说,你必须要“输入”一个指令之后,“硬件“才会通过你下达的指令来工作!那么硬件如何知道你下达的指令呢?那就是 kernel(核心)的控制工作了!也就是说,我们必须要通过“Shell”将我们输入的指令与 Kernel 沟通,好让 Kernel 可以控制硬件来正确无误的工作!基本上,我们可以通过下面这张图来说明一下:
以上内容摘自《鸟哥的 L ...
Linux
未读进程控制 —— 进程程序替换1. 替换原理进程程序替换是指在一个已经存在的进程中,通过系统调用将当前进程的代码、数据等全部替换为新程序的内容,也就是说,新程序加载到当前进程的地址空间中,原来进程的内容被完全覆盖。在这一过程中,进程的 PID 保持不变,但内存空间、寄存器的内容和代码逻辑均变为新程序的内容。
【关键点】
进程替换不创建新进程,而是复用现有进程的 PID,这对需要快速切换任务、降低资源开销有很大好处。
一旦替换成功,原进程的代码 立即终止,从新程序的 main 函数开始执行。
替换过程会关闭原进程中打开的文件描述符(除非这些描述符被标记为在 exec 之后保留),fcntl(fd, F_SETFD, FD_CLOEXEC) 标记文件描述符在 exec 后关闭(了解)。
2. execl 的单进程使用1. 函数原型12345678910int execl(const char* path, const char* arg, ..., (char*)NULL);注意:execl 接受变长参数,需要以 NULL 结束参数列表,参数顺序要求严格,第一个参数通常写为程序文件的 ...
Linux
未读进程控制 —— 进程等待1. 进程等待必要性
当父进程通过 fork() 创建了子进程后,子进程终止时,其退出信息必须由父进程读取,父进程如果不管不顾,就可能造成 僵尸进程 的问题,进而造成内存泄漏。
另外,进程一旦变成僵尸状态,那就刀枪不入,“杀人不眨眼”的 kill -9 也无能为力,因为谁也没有办法杀死一个已经死去的进程。
最后,父进程派给子进程的任务完成的如何,我们需要知道。如子进程运行完成,结果对还是不对,或者是否正常退出。
父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息。
如果不等待会怎样?
子进程退出了,但父进程没有调用 wait() 系列函数。
子进程的“退出状态”会保留在内核中,直到父进程读取它。
此时子进程的 PCB 没有完全释放,占用系统资源。
如果产生大量僵尸进程,系统资源将耗尽,导致无法创建新进程。、
所以:父进程需要“等待”子进程终止并获取其退出状态,以释放系统资源。
面试点拨: 如果不调用 wait() 会怎样?
回答:子进程的退出信息留在内核,PCB 未释放,形成僵尸进程,长期不回收会占满系统资源。
2. 常用等待方 ...
Linux
未读进程控制 —— 终止进程一、进程退出场景从我们的视角来看进程终止的场景一般就是以下三种:
代码运行完毕,结果正确(一般不关心)。
代码运行完毕,结果不正确。
代码异常终止。
但是进程也可能因多种原因终止,比如:
场景
说明
正常完成任务
程序执行完所有代码逻辑后退出
异常错误终止
遇到不可恢复的错误(如段错误、除零错误)
主动终止
调用退出函数(exit()/_exit())或通过 return 退出
被动终止
收到终止信号(如 SIGKILL、SIGTERM)
被父进程杀死
父进程调用 kill() 函数发送信号,使子进程退出。
看进程终止的角度、进程终止的原因等不同方面来解释进程的终止,虽然说法上不同,但也大同小异,我们只需要记住一点:
所有进程的退出方式都可以归为两大类:正常退出 和 异常退出,而主动或被动,是从行为发起方角度来分的。进程出现异常,本质是我们的进程收到了对应的信号!!
二、进程的退出码
我们都知道 main 函数是代码的入口,但实际上 main 函数只是用户级别代码的入口,main 函数也是被其他函数调用的, ...
使用 Git 从 HTTPS 切换至 SSH起因是我在 Linux 中使用 git push 推送经常卡住或失败,真的很烦,于是选择 切换成 SSH ,可以提高稳定性和体验,比较适合在 Linux 系统开发环境中长期使用。当然本文的方法也同样适用于 Windows。
1. 确认是否已生成 SSH 密钥对先检查是否已有 .ssh/id_rsa 文件:
1ls ~/.ssh
如果看到了 id_rsa 和 id_rsa.pub 就说明已经有了密钥对。如果没有,就执行下面的命令生成:
1ssh-keygen -t rsa -b 4096 -C "你的邮箱"
一路回车即可生成(个人使用,建议不设密码短语,会方便些)。
2. 将 SSH 公钥添加到远程仓库平台(如 GitHub / Gitee)1. 复制公钥内容1cat ~/.ssh/id_rsa.pub
复制输出的整段文本(以 ssh-rsa 开头,以邮箱结尾)。对应 Windows 实际路径为 C:\Users\你的用户名\.ssh\。
2. 添加到远程平台1. GitHub:
登录 GitHub。
点 ...
Linux
未读进程控制 —— 进程创建一、fork() 函数基础1. fork() 的作用
创建子进程:通过复制父进程的地址空间生成一个新进程。
调用一次,返回两次:
父进程返回子进程的 PID(即 > 0 or 正数)。
子进程返回 0。
失败返回 -1。
1pid_t fork(void);
2. 写时拷贝(Copy-On-Write, COW)
机制:fork 时不会立刻复制父进程的所有内存页。fork() 后,父子进程 共享物理内存(共享内存页(只读)),直到一方尝试修改数据时,内核才复制该内存页。
修改时触发“页错误”
操作系统才会为该进程分配新的物理页,完成“真正拷贝”
优点:
提升效率: 减少 fork() 的开销(避免立即复制全部内存)。
节省内存开销: 节省物理内存(共享未修改的页)。
[!NOTE]
通常,父子代码共享,父子再不写入时,数据也是共享的,当任意一方试图写入,便以写时拷贝的方式各自一份副本。具体见下图:
二、代码示例示例 1:基础 fork() 使用123456789101112#include <stdio.h ...
Linux
未读程序地址空间入门程序的 地址空间 是操作系统为每个程序分配的内存区域,它决定了程序如何访问存储在计算机内存中的数据。程序地址空间包括了多个部分,每一部分有不同的用途。通过合理管理地址空间,操作系统可以有效地进行内存分配和保护。
1. 地址空间的划分程序的地址空间通常分为多个段,每个段具有不同的功能。这些段的划分通常是由操作系统定义的。下图是基于 kernel 2.6.32 和 32位平台 的典型空间布局图:
然而,一个标准的程序地址空间布局图(32 位系统)包括:
更详细点来说则是:
1234567891011121314151617181920212223242526+------------------------+ <-- 0xC0000000(内核空间起始,用户不可访问) | 内核空间 | +------------------------+ <-- 0xBFFFFFFF(用户空间结束) | 栈(Stack) | ↓ 向低地址增长 | - 主线程栈 | +------ ...