- 论坛徽章:
- 0
|
shell在执行一个外部程序的时候,会首先fork一个子进程,然后exec,替换进程空间
经常看到论坛上有人说在使用管道的时候,当前shell会产生一个子shell来执行管道中的命令
这使我产生了一个疑问:单独执行两个外部命令cmda和cmdb(或者使用cmda; cmdb这种方式) 与
cmda | cmdb这两种执行方式是不是产生的进程个数是不一样的?
为了验证我的猜测,写了一个小程序,用来打印进程的PID和PPID:
- liuxiang@MacBookPro: ~/casecode/sh $ echo '#include <stdio.h>
- > #include <unistd.h>
- > int main(int argc, char *argv[]){
- > printf("PID: %d\n", getpid());
- > printf("PPID: %d\n", getppid());
- > }' > printppid.c
- liuxiang@MacBookPro: ~/casecode/sh $ gcc printppid.c -o printppid
复制代码
我使用的是bash,当前shell的PID是 1827:
- liuxiang@MacBookPro: ~/casecode/sh $ echo $SHELL
- /bin/bash
- liuxiang@MacBookPro: ~/casecode/sh $ echo $$
- 1827
复制代码
下面是执行printppid的结果,可以看到父进程是1827,也就是当前shell
- liuxiang@MacBookPro: ~/casecode/sh $ ./printppid
- PID: 2331
- PPID: 1827
复制代码
下面通过管道执行两次printppid,为使前一个printppid的输出也能打印出来,将其标准输出重定向到标准错误.
可以看到,管道左右两个进程的父进程都是1827,也就是说这个过程中,根本就没有什么子shell.
单独执行两个外部命令cmda和cmdb(或者使用cmda; cmdb这种方式) 与 cmda | cmdb这两种执行方式产生的进程个数也就应该是一样的
- liuxiang@MacBookPro: ~/casecode/sh $ ./printppid >&2 | ./printppid
- PID: 2332
- PPID: 1827
- PID: 2333
- PPID: 1827
复制代码
疑问好像可以得到答案了。
但是有一个问题却使我更迷糊了:
- liuxiang@MacBookPro: ~/casecode/sh $ var=1
- liuxiang@MacBookPro: ~/casecode/sh $ echo $var
- 1
- liuxiang@MacBookPro: ~/casecode/sh $ var=2 | ./printppid
- PID: 2356
- PPID: 1827
- liuxiang@MacBookPro: ~/casecode/sh $ echo $var
- 1
复制代码
为什么变量var的值没有变成2?
我想在使用管道的过程当中,对于shell内建命令以及shell赋值语句等
是不是shell也fork了一个子进程,然后没有exec,而是直接使用fork出来的这个子进程
执行了内建命令或者赋值语句?
所以我进一步验证,发现也不是我想的这么回事, 内建命令就是在当前的这个交互shell上执行的。
- liuxiang@MacBookPro: ~/casecode/sh $ eval 'echo $$' >&2 | ./printppid
- 1827
- PID: 2389
- PPID: 1827
复制代码
那么,哪位DX能给我解释解释为什么在经过var=2 | somecmd 之后,var在当前shell里的值没有变? |
|