免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12345下一页
最近访问板块 发新帖
查看: 15561 | 回复: 48
打印 上一主题 下一主题

还是管道和子shell的问题,越来越糊涂了 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-06-13 16:17 |只看该作者 |倒序浏览
shell在执行一个外部程序的时候,会首先fork一个子进程,然后exec,替换进程空间
经常看到论坛上有人说在使用管道的时候,当前shell会产生一个子shell来执行管道中的命令
这使我产生了一个疑问:单独执行两个外部命令cmda和cmdb(或者使用cmda; cmdb这种方式) 与
cmda | cmdb这两种执行方式是不是产生的进程个数是不一样的?

为了验证我的猜测,写了一个小程序,用来打印进程的PID和PPID:


  1. liuxiang@MacBookPro: ~/casecode/sh $ echo '#include <stdio.h>
  2. > #include <unistd.h>
  3. > int main(int argc, char *argv[]){
  4. >   printf("PID: %d\n", getpid());
  5. >   printf("PPID: %d\n", getppid());
  6. > }' > printppid.c
  7. liuxiang@MacBookPro: ~/casecode/sh $ gcc printppid.c -o printppid
复制代码


我使用的是bash,当前shell的PID是 1827:


  1. liuxiang@MacBookPro: ~/casecode/sh $ echo $SHELL
  2. /bin/bash
  3. liuxiang@MacBookPro: ~/casecode/sh $ echo $$
  4. 1827
复制代码


下面是执行printppid的结果,可以看到父进程是1827,也就是当前shell

  1. liuxiang@MacBookPro: ~/casecode/sh $ ./printppid
  2. PID: 2331
  3. PPID: 1827
复制代码


下面通过管道执行两次printppid,为使前一个printppid的输出也能打印出来,将其标准输出重定向到标准错误.
可以看到,管道左右两个进程的父进程都是1827,也就是说这个过程中,根本就没有什么子shell.
单独执行两个外部命令cmda和cmdb(或者使用cmda; cmdb这种方式) 与 cmda | cmdb这两种执行方式产生的进程个数也就应该是一样的

  1. liuxiang@MacBookPro: ~/casecode/sh $ ./printppid >&2 | ./printppid
  2. PID: 2332
  3. PPID: 1827
  4. PID: 2333
  5. PPID: 1827
复制代码


疑问好像可以得到答案了。
但是有一个问题却使我更迷糊了:

  1. liuxiang@MacBookPro: ~/casecode/sh $ var=1
  2. liuxiang@MacBookPro: ~/casecode/sh $ echo $var
  3. 1
  4. liuxiang@MacBookPro: ~/casecode/sh $ var=2 | ./printppid
  5. PID: 2356
  6. PPID: 1827
  7. liuxiang@MacBookPro: ~/casecode/sh $ echo $var
  8. 1
复制代码

为什么变量var的值没有变成2?
我想在使用管道的过程当中,对于shell内建命令以及shell赋值语句等
是不是shell也fork了一个子进程,然后没有exec,而是直接使用fork出来的这个子进程
执行了内建命令或者赋值语句?
所以我进一步验证,发现也不是我想的这么回事, 内建命令就是在当前的这个交互shell上执行的。

  1. liuxiang@MacBookPro: ~/casecode/sh $ eval 'echo $$' >&2 | ./printppid
  2. 1827
  3. PID: 2389
  4. PPID: 1827
复制代码


那么,哪位DX能给我解释解释为什么在经过var=2 | somecmd 之后,var在当前shell里的值没有变?

论坛徽章:
0
2 [报告]
发表于 2009-06-13 16:37 |只看该作者
那么,哪位DX能给我解释解释为什么在经过var=2 | somecmd 之后,var在当前shell里的值没有变?


引自13问
$ A=B C        # 空白鍵未被關掉,作為 IFS 處理。
        $ C: command not found.
        $ echo $A
        
        $ A="B C"        # 空白鍵已被關掉,僅作為空白鍵處理。
        $ echo $A
        B C

论坛徽章:
0
3 [报告]
发表于 2009-06-13 16:46 |只看该作者

论坛徽章:
7
荣誉版主
日期:2011-11-23 16:44:17子鼠
日期:2014-07-24 15:38:07狮子座
日期:2014-07-24 11:00:54巨蟹座
日期:2014-07-21 19:03:10双子座
日期:2014-05-22 12:00:09卯兔
日期:2014-05-08 19:43:17卯兔
日期:2014-08-22 13:39:09
4 [报告]
发表于 2009-06-13 16:48 |只看该作者
虽然管道左边的var=2是个内置命令,但是我猜应该和普通命令一样都是在子shell中运行的。

论坛徽章:
0
5 [报告]
发表于 2009-06-13 16:48 |只看该作者

回复 #2 ywlscpl 的帖子

A=B C  是将B赋给A,然后把A作为环境变量传给C,
那A=B | C呢?反正不是将A作为环境传给C的

论坛徽章:
0
6 [报告]
发表于 2009-06-13 16:53 |只看该作者

回复 #5 lululau 的帖子

我只是解释var=2未在当前shell生效这个问题啊?

加管道后是不会影响后面的子shell的

  1. [root@Mylinux ~]# cat mysh
  2. #!/bin/bash
  3. echo $a
  4. [root@Mylinux ~]# a="b" ./mysh
  5. b
  6. [root@Mylinux ~]# a="b" |./mysh

  7. [root@Mylinux ~]#
复制代码

论坛徽章:
23
15-16赛季CBA联赛之吉林
日期:2017-12-21 16:39:27白羊座
日期:2014-10-27 11:14:37申猴
日期:2014-10-23 08:36:23金牛座
日期:2014-09-30 08:26:49午马
日期:2014-09-29 09:40:16射手座
日期:2014-11-25 08:56:112015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:0315-16赛季CBA联赛之山东
日期:2017-12-21 16:39:1915-16赛季CBA联赛之广东
日期:2016-01-19 13:33:372015亚冠之山东鲁能
日期:2015-10-13 09:39:062015亚冠之西悉尼流浪者
日期:2015-09-21 08:27:57
7 [报告]
发表于 2009-06-13 16:56 |只看该作者

回复 #1 lululau 的帖子

为什么 ./printppid >&2 | ./printppid 与 ./printppid 产生的进程个数不一样,这个我不懂,但你的实验确实证明了,他们都是在子shell中执行的,因为他们的PID都变了,而且PPID都是当前shell的PID。

子shell中的操作,是不会改变父shell的变量的。

论坛徽章:
0
8 [报告]
发表于 2009-06-13 17:06 |只看该作者

回复 #7 ly5066113 的帖子

我理解的子shell应该指的是,比如有一个shell脚本,script.sh,这个脚本里执行若干命令:cmd1 cm2 ... 等等。
当你在./script.sh在执行这个脚本的时候,当前的交互shell会产生一个子shell来解释执行这个脚本,也就是说这个子shell
是cmdx的父进程(当然cmdx得是外部命令),而当前的交互shell是cmdx的爷爷进程

论坛徽章:
0
9 [报告]
发表于 2009-06-13 17:10 |只看该作者

回复 #4 r2007 的帖子

不知道管道中赋值语句是不是在子进程中执行的
至少我知道管道中的eval(It's a shell builtin)不是在子进程中执行的:

eval 'echo $$ >&2' | eval 'echo $$'

论坛徽章:
23
15-16赛季CBA联赛之吉林
日期:2017-12-21 16:39:27白羊座
日期:2014-10-27 11:14:37申猴
日期:2014-10-23 08:36:23金牛座
日期:2014-09-30 08:26:49午马
日期:2014-09-29 09:40:16射手座
日期:2014-11-25 08:56:112015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:0315-16赛季CBA联赛之山东
日期:2017-12-21 16:39:1915-16赛季CBA联赛之广东
日期:2016-01-19 13:33:372015亚冠之山东鲁能
日期:2015-10-13 09:39:062015亚冠之西悉尼流浪者
日期:2015-09-21 08:27:57
10 [报告]
发表于 2009-06-13 17:28 |只看该作者

回复 #8 lululau 的帖子

http://bbs.chinaunix.net/viewthread.php?tid=733138

subshell 的产生情况会有很多种,例如:
1、cmd1 | cmd2
2、(cmd)
3、`cmd`
。。。。。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP