模型配合环境变量操作 */ #include // 标准输入输出流 #include // C标准IO库 #include 标准提示符 输入处理流水线 GetCommandLine()实现三步处理: 安全读取(fgets防溢出) 去除换行(\n→\0) 空输入过滤...工作机制 首次调用:传入待处理字符串和分隔符 后续调用:使用NULL继续处理原字符串 修改原理:通过插入\0分割字符串,返回每个token的起始地址 execvp特性 v:参数以数组形式传递(需NULL...结尾) p:自动搜索PATH环境变量中的可执行文件 执行成功时替换当前进程映像,失败返回-1 waitpid作用 防止僵尸进程产生 同步父子进程执行顺序 可获取子进程退出状态(本实现未使用) 后续扩展...(SIGINT, [](int){ /* 处理Ctrl+C */ }); 从模仿到超越 通过这个微型Shell的实现,我们掌握了以下核心技能: 环境变量操作:getenv的灵活使用 进程管理:fork-exec-wait
Linux管道及重定向 对shell有一定了解的人都知道,管道和重定向是 Linux 中非常实用的 IPC 机制。在shell中,我们通常使用符合‘|’来表示管道,符号‘>’和‘同时双向传输需要使用两个管道。管道又可以分为匿名管道和命名管道,而shell中使用到的是匿名管道,所以本文仅描述匿名管道。...至此管道就算创建成功了。 把管道作为标准输入输出 管道创建成功后,就可以直接使用 read()和 write()函数对管道进行数据的读写。...而因为shell中都是使用标准输入输出对管道进行读写的,例如ls | grep main.c就是将 ls 的标准输出写到了管道写端,而 grep 的标准输入则从管道读端读取,所以本文也只描述此方法。...文件重定向 文件重定向其实与上面管道重定向到标准输入输出很类似,甚至可以直接采用上面所说的方法来实现。但是此处将讲述一种更加简洁的方法实现。
$ cmd1 | cmd2 | cmd3 | cmd4 | cmd5 我们要使用 Python 语言,因为 Go 和 Java 语言都不支持 fork 函数。...第一个指令和最后一个指令只有一个管道,中间的指令有两个管道。管道的标识是它的一对读写描述符(r, w)。 ? 图片 左边管道的读描述符 left_pipe[0] 对接进程的标准输入。...右边管道的写描述符 right_pipe[1] 对接进程的标准输出。调整完描述符后,就可以使用 exec 函数来执行指令。 ?...理论上使用管道可以串接非常多的进程输入输出流。...if pid > 0: # 父进程来执行指令 # 同时传入左边和右边的管道(可能为空) run_cmd(cur_cmd, left_pipe,
1. fork函数介绍 在linux中fork函数是非常重要的函数,它可以从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。...fork函数的返回值如下: 1、在父进程中,fork返回新创建的子进程的PID号。 2、在子进程中,fork返回0; 3、如果出现错误,fork返回一个负值。...fork函数创建子进程的过程: 使用fork函数得到的子进程是父进程的一个复制品,它从父进程继承了进程的所有资源,相当于就是父进程的一个副本。...\n"); return 0; } 4. system函数 system函数用于启动新的子进程,这个函数内部就是使用fork+exec+wait函数组合实现的。...案例: 使用fork函数创建5个子进程同时运行 #include #include int main() { int i; pid_t pid
输入命令所能带的参数个数,只受 到系统键盘输入缓冲区长度(以及shell输入缓冲区长度)的限制,该缓冲区的缺省长度是4096个字节。...实现时要解决的主要问题有: **1.1正确理解并使用系统调用fork(),execve()和waitpid(),特别是execve()函数。**fork()函数创建一个新的进程。...当fork()函数返回值为0时表示处 于子进程中;而返回值大于0时表示处于父进程中,此时的返回值是子进程的进程id。因此,fork()的返回值可以用来划分仅仅适合父进程 和子进程执行的程序段。...因此,我们可以使用execvp函数,仅需传入之前构造的argv参数,从而间接执行系统调用execve: if ((pid=fork())fork error: %s\n", strerror...,若有重定向输入输出,则在redirect_stdin或 redirect_stdout中处理,execvp填入可执行文件参数,子进程开始执行,若出错才会执行下面的execvp error打印错误语句,
单进程中的管道:int fd[2] 使用文件描述符fd[1],向管道写数据。 使用文件描述符fd[0],从管道中读数据。 注意: 单进程中的管道无实际用处,管道用于多进程间通信。...5: 把管道作为标准输入和标准输出 把管道作为标准输入和标准输出的优点: 子进程使用exec启动新进程时,就不需要再把管道的文件描述符传递给新程序了。...可以标准输入(或标准输出)的程序。 实现流程: 使用dup复制文件描述符。 用exec启动新程序后,原进程中已打开的文件描述符扔保持打开。即可共享原进程中的文件描述符。...B的标准输入(使用fwirte写入)。...当使用"r"时,该FILE*指向外部进程的标准输出。 当使用"w"时,该FILE*指向外部程序的标准输入。
在 Node.js 中,cluster.fork 与 POSIX 的 fork 略有不同:虽然从进程仍旧是 fork 创建,但是并不会直接使用主进程的进程映像,而是调用系统函数 execvp 让从进程使用新的进程映像...例如,在方法 spawn 中,如果需要主从进程之间建立 IPC 管道,则通过环境变量 NODE_CHANNEL_FD 来告知从进程应该绑定的 IPC 相关的文件描述符(fd),这个特殊的环境变量后面会被再次涉及到...其中 send 只是对 _send 的封装;通常,_send 只是把消息 JSON 序列化之后写入管道,并最终投递到接收端。...其实,通过指定 socketpair 的第一个参数为 AF_UNIX,表示创建匿名 UNIX 域套接字(UNIX domain socket),这样就可以使用系统函数 sendmsg 和 recvmsg...进程级文件描述符表中,0-2分别是标准输入stdin、标准输出stdout和标准错误输出stderr,那么可用的第一个文件描述符就是3,socketpair 显然会占用从进程的第一个可用文件描述符。
fork子进程是为了执行新程序(fork创建了子进程后,子进程和父进程同时被OS调度执行,因此子进程可以单独的执行一个程序,这个程序宏观上将会和父进程程序同时进行) 可以直接在子进程的if中写入新程序打代码...但这样不够灵活,因为我们只能把子进程程序的源代码贴过来执行(必须知道源代码,而且源代码太长了也不好控制) 使用exec族函数运行新的可执行程序。...主进程为父进程,fork创建了子进程后在子进程中exec来执行hello,达到父子进程分别做不同程序同时(宏观上)运行的效果。...) { printf("4------------execvp------------\n"); if( execvp( "ls", arg ) < 0 ) {...,列表以NULL指针作为结束标志 *e 函数传递指定参数envp,允许改变子进程的环境,无后缀e时,子进程使用当前程序的环境 */ if( fork() == 0 ) { printf
优化策略 在第一版代码中,由于功能较为简单,未采用模块化设计;同时,其实现也相对单一,仅支持非阻塞命令的执行。...其中,一些细节的实现如下记录: BuildConnectAsTcpServer 当接收到客户端成功接入时,需如下处理: ① 将服务端socket文件描述符fd,通过dup2重定向至标准输入(stdin)...然后将整个命令字符串按空格分割成多个参数,存储在一个 std::vector 中。 ② 创建子进程:通过 fork() 创建一个子进程。...在子进程中,使用 execvp 函数执行指定的 shell 命令。execvp 会接管子进程,用新的程序替换当前进程的镜像。...多进程模式便于管理 shell 执行的子进程,而 execvp 则简化了命令输出的重定向。 实现后,即使在非Linux平台一样能够使用Shell指令调试目标设备,还是比较方便的。
像Linux进程那样,一个进程可以fork一个子进程,并让这个子进程exec另外一个程序。在Python中,我们通过标准库中的subprocess包来fork一个子进程,并运行一个外部的程序。...subprocess包中定义有数个创建子进程的函数,这些函数分别以不同的方式创建子进程,所以我们可以根据需要来从中选取一个使用。...另外subprocess还提供了一些管理标准流(standard stream)和管道(pipe)的工具,从而在进程间使用文本通信。...、标准输出和标准错误如下属性分别表示: child.stdin child.stdout child.stderr 可以在Popen()建立子进程的时候改变标准输入、标准输出和标准错误,并可以利用subprocess.PIPE...将多个子进程的输入和输出连接在一起,构成管道(pipe);如没有写stdin和stdout,默认将子进程执行结果打印至屏幕上,而不是保存于内存中 例1: #!
man 2查询,说明是系统级函数 其他的exec函数是通过语言封装的系统调用,使用man 3查询 Linux系统的底层实现 完全控制环境变量 execle()和execve() 基本使用方式和原来...用C语言写的程序都有main函数,可以接受argv和env,所以当使用**exec*e**系列的函数传入自定义的env时实际上就是给要执行的进程main传入env。...non_exist_cmd", NULL) == -1) { perror("exec失败"); exit(EXIT_FAILURE); } 文件描述符保留 所有打开的文件描述符保持打开状态 特别注意管道和...pid_t pid = fork(); if (pid == 0) { // 子进程 execvp(command, args); exit(EXIT_FAILURE); // 只有exec...正确进行错误处理至关重要 结合fork使用是常见模式 在实际开发中: 优先考虑execlp/execvp的便利性 需要环境控制时使用execle/execve 动态参数建议使用数组形式的execv系函数
(2)execlp和execvp 这两个函数在上面2个基础上加了p,较上面2个来说,区别是:上面2个执行程序时必须指定可执行程序的全路径(如果exec没有找到path这个文件则直接报错),而加了p的传递的可以是...重设文件权限掩码 新建文件的权限受文件权限掩码影响 022:只写 新建文件默认执行权限:666 真正的文件执行权限:666&(~umask) 方法:通过umask 5.关闭不需要的文件描述符 0,1,2:标准输入...域套接字 (4)信号 linux的IPC机制-管道 管道(无名管道) (1)管道通信的原理:内核维护的一块内存,有读端和写端(管道是单向通信的) (2)管道通信的方法:父进程创建管理后fork子进程,子进程继承父进程的管道...(2)有名管道的使用方法:固定一个文件名,2个进程分别使用mkfifo创建fifo文件,然后分别open打开获取到fd,然后一个读一个写 (3)管道通信限制:半双工(注意不限父子进程,任意2个进程都可...我们当前进程和syslogd进程本来是没有任何关系的,但是我们当前进程可以通过调用openlog打开一个和syslogd相连接的通道,然后通过syslog向syslogd发消息,然后由syslogd来将其写入到日志文件系统中
让子进程执行父进程的一部分代码 红框中的代码实际上是父进程的代码,在没有执行fork之前代码就有了,在没有创建子进程之前,父进程的代码加载到内存了,子进程被创建出来是没有独立的代码,这个代码是父进程的代码.../可执行程序就变成进程了,CPU调度进程 ,打印出代码中的打印语句,同时调用程序替换execl,将ls程序执行起来了 ---- [yzq@VM-8-8-centos nn]$ file /bin/ls...int execvp(const char *file, char *const argv[]); 带p:代表当执行程序的时候,只需要指定程序名即可,系统会自动在PATH环境变量中查找 v代表vector...,但是这是个死循环,所以什么都不会显示 ---- ---- ---- 执行可执行程序后即可显示命令行 fgets 使用出现空格问题 fgets 标准输入 按行获取 char *fgets(char...*s, int size, FILE *stream); 从特定的标准输入当中获取对应的命令行输入,把对应的数据放在缓冲区中 ---- ---- ---- 执行可执行程序后,发现在命令行中输入 ls
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。...关于 操作系统 领域进程的概念:操作系统(2)进程 ---- 进程原语 fork #include pid_t fork(void); 功能:子进程复制父进程中的0~3g空间和PCB...(1)复制父进程的系统环境(放心,只要是你开的进程,肯定有父进程) (2)在内核中建立进程结构 (3)将结构插入到进程列表,便于维护 (4)分配资源给该进程 (5)复制父进程的内存映射消息 (6)管理文件描述符和链接点...exec族 fork子进程是为了执行新程序(fork创建了子进程后,子进程和父进程同时被OS调度执行,因此子进程可以单独的执行一个程序,这个程序宏观上将会和父进程程序同时进行) 使用exec族函数运行新的可执行程序...主进程为父进程,fork创建了子进程后在子进程中exec来执行hello,达到父子进程分别做不同程序同时(宏观上)运行的效果。
bash 就是一个运行中的进程,因为进程间具有独立性,因此可以同时存在多个 bash,这也是多用户登录 Linux 可以同时使用 bash 的重要原因 系统自带的 bash 是一个庞然大物,我们只需根据其本质...Linux 中的大部分指令由 指令 [选项] 构成,在 指令 和 [选择] 间有空格 常规的 scanf 无法正常读取指令,因为空格会触发输入缓冲区刷新 这里主要使用 fgets 逐行读取,可以读取到空格...execvp,理由: v 表示 vector,正好和我们的 argv 表对应 p 为 path,可以根据 argv[0](指令),在 PATH 中寻找该程序并替换 当然也可以使用 execve 系统级替换函数...//子进程进行程序替换 pid_t id = fork(); if(id == 0) { //直接执行程序替换,这里使用 execvp execvp(argv[0], argv); exit...argv[1] 中的内容是不断变化的,不能直接使用 一般用户自定义的环境变量,在 bash 中需要用户自己维护 最好的方案就是使用缓冲区进行环境变量的拷贝放置,因为缓冲区中的内容不易变 错误体现:直接使用
第8章 进程和程序:编写命令解释器sh Unix通过将可执行代码装入进程并执行它来运行一个程序.进程是 一个程序所需的内存空间和其他资源的集合 每个运行中的程序在自己的进程中运行.每个进程都有一个唯一的...进程ID,所有者,大小及其他属性 系统调用fork通过复制进程来建立一个几乎和原来进程完全相同的 副本进程.这个新建的进程被称为子进程 一个程序通过调用exec函数族在当前进程中执行一个新的程序 一个程序能通过调用...: 1 运行一个程序 2 建立一个进程 3 等待exit() 一个程序运行另一个程序: 调用execvp 内核将新程序载入到当前进程,替代当前进程的代码和数据,因此最好 还是fork一个子进程,然后子进程来调用...execvp 如何建立新进程: fork 系统调用fork正是解决shell只能运行一条命令这个问题所需要的 父进程等待子进程结束: 进程调用wait等待子进程结束 pid = wait(&status...设计的基础 全局变量和fork/exec 全局变量会破坏封装原则,但有时候去掉会更糟糕.Unix提供方法来建立 全局变量,环境是一些传递给进程的字符串型变量集合 execvp不是一个系统调用,而是一个库函数
文件描述符继承:除非显式关闭,进程的文件描述符会被继承到新程序中,并且它们的状态(如文件指针位置)也会被继承。...这里内存空间替换更深层的其实是连接虚拟地址和物理地址之间页表指向的改变,关于页表的内容我们在前面讲进程地址空间时有讲过,作为拔高内容了解即可 进程替换通常与fork系统调用结合使用。...它允许一个进程加载并执行指定路径的程序,同时传递命令行参数和环境变量。...进程替换通常与fork结合使用,fork创建一个新进程,而exec替换子进程的程序映像。这种模式广泛应用于Shell的实现、任务调度、进程间通信等领域。...理解并熟练使用exec系列函数,是编写高效、灵活的系统程序的关键之一。希望本文通过丰富的代码示例和详细的解释,能够帮助你更好地掌握Linux中的进程替换机制。
fork系统调用的作用是复制一个进程,从而出现两个几乎一样的进程。一般来说,fork后是父进程先执行还是子进程先执行是不确定的,取决于内核所实使用的调度算法。...fork调用的神奇之处在于被调用一次,能够返回两次,返回结果可能有3种情况: 父进程中:fork返回新创建的子进程的ID 子进程中:fork返回0 出现错误:fork返回负值 fork出错的原因有2:...使用exec函数族,一般要加上错误判断语句,因为exec函数易由多种原因运行失败: 找不到文件或路径:errno被设置为ENOENT 数组argv和envp忘记使用NULL结束:errno被设置为EFAULT...在Linux的标准函数库中,有一套被称为“高级I/O的函数”,如printf()、fopen()等,也被称为“缓冲I/O(buffered I/O)”,其特征是对应每一个打开的文件,在内存中都有一片缓冲区...等待一个指定进程组中的任何子进程,其进程ID为pid的绝对值 参数options提供一些额外的选项来控制waitpid,包括WNOHANG和WUNTRACED两个选项,这是两个常数,可以用|运算符连接使用
下面我们直接来看一看如何去实现shell命令行解释器: 总体分为(整体需要循环哦): 1.输出提示符 2.输入和获取命令 3.fork创建子进程 4.内建命令 ---- 输出提示符 这里的提示字符为用户名...,在这个地方哦可以用fflush(stdout)刷新缓冲区 输入和获取命令 输入 我们需要获取一行的内容,利用fgets函数获取,同时,可以定义一个lineCommand[NUM]数组 char*s...fork创建进程 利用fork创建子进程,同时父进程需要等待子进程退出返回结果 另外我们还需要选择替换函数execvp:首先替换函数需要先带上v,可将所有的执行参数放入数组中统一传递,其次还要选择带上...p,我们输入的只有程序命令,带上p会自动在环境变量中寻找 至此,基本的框架我们已经搞定了。...内建命令 我们在运行自己写的shell的时候,发现输入cd …输入cd path等命令时发现路径并没有改变!
为什么Linux执行当前目录下的可执行文件要使用'./'前缀呢? 必须使用./的原因? 把'.'排除在root用户的PATH之外的原因? 必须使用./的原因?...因为shell使用了fork() + execvp/execlp函数来启动新程序,这时如果没有使用绝对路径(‘/‘开头)或者使用’..../xxx’,那么这个库函数的行为就是在环境变量PATH中寻找你指定的filename。...int execvp(const char *filename, char *const argv[]); 那么,问题来了。root用户的PATH通常是不包含‘.’的,也就是说不包含当前目录。...防止root用户不小心执行了当前工作目录下与标准命令同名的恶意程序。 不小心把命令拼错,执行了不想执行的程序(例如ls写成了sl)
领取专属 10元无门槛券
手把手带您无忧上云