免费注册 查看新帖 |

Chinaunix

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

请帮忙看看变量为什么没有被赋值 [复制链接]

论坛徽章:
0
1 [报告]
发表于 2006-11-19 23:21 |显示全部楼层
给您个资料看,这里讲得很明白~~
http://www.unix.org.ua/orelly/unix/ksh/ch07_02.htm

论坛徽章:
0
2 [报告]
发表于 2006-11-20 11:47 |显示全部楼层
  1. outvar=abcd
  2. cat tmp.input | while read test
  3. do
  4.     echo "pid: $$"
  5.     echo "$outvar"
  6.     test2=$test
  7.     set | grep '^test2'
  8.     ps
  9. done
复制代码

我来尝试讲解下这段,请大家帮忙偵谬。
第一句我添加了一个变量赋值,然后在while中增加了一个echo此变量的语句,第一句只是设定环境,我们不做讨论
首先,这段语句(从cat起始,done结束)其实提交给shell时是作为一个pipeline一次性提交给shell解释并执行的(注意,是这段语句而不仅仅是
  1. cat tmp.input | while read test
复制代码
这一句。关键就在此处,因为shell是先将整个pipeline解释后才将解释好的command行送去执行。这个先后顺序很重要!
shell将此pipeline最终解释成下面的样子

  1. cat tmp.input | while read test
  2. do
  3.     echo "pid: 872" #$$的变量替换先于整个语句的执行,因此当它被替换时,此shell还并没有fork subshell,所以当然$$还是脚本所起的subshell的PID
  4.     echo "abcd" #同理,此时subshell还没有被fork,那么这个$outvar当然不在subshell里,何来subshell继承变量的问题呢?
  5.     test2=$test #这里暂时不会被变量替换,因为此时$test已经被指定了从while命令的标准输入,即cat命令的标准输出来获得变量值。
  6.     set | grep '^test2' #这里留一个悬念,set命令并不像前面一样是因为变量替换先于命令执行而导致直接取到了变量值,那么为什么set能获得当前shell中的所有变量呢?
  7.     ps #这里要注意一个知识点,即任何外部命令都会fork一个当前shell的subshell。ps命令会导致shell fork一个ps进程,这个进程的功用是查看当前shell所在进程树的进程信息,PID为3648的是shell脚本所在的环境shell、PID为872的shell脚本fork的subshell、PID为3448的是因为"|"而为while所fork的subshell,PID为2556的是ps命令所fork的subshell,此subshell的父shell是while所fork那个。而其他的命令并非不fork subshell,但ps命令只能监控到它执行的那个时间点的进程信息,因此看不到其他命令fork的subshell
  8. done
复制代码

整个pipeline解释完毕,shell设定I/O重定向及其他一些细节,然后执行整个语句。执行过程如下
同时fork两个subshell,一个是cat命令的,一个是while命令的,cat命令输出标准输出,之后此subshell退出,同时while通过管道从标准输入获得输入(这就是为什么ps命令没看到cat命令所fork的subsehll,因为它先于while退出)。while所fork的这个subshell此时作为当前shell来顺次执行循环体里的语句(其实这些语句对于while来说,可以被认为是它的参数),每个外部命令也都将fork subshell。当标准输入的信息完全接收完毕,循环条件结束,subshell退出。

PS:关于shell解释语句中的各个步骤,我在这里就不详细说明了,有兴趣研究下面的链接就清楚了
http://www.unix.org.ua/orelly/unix/ksh/ch07_03.htm

[ 本帖最后由 一梦如是 于 2006-11-20 11:53 编辑 ]

论坛徽章:
0
3 [报告]
发表于 2006-11-20 11:52 |显示全部楼层
原帖由 Edengundam 于 2006-11-20 11:28 发表
我知道了man sh
$      Expands to the process ID of the shell.  In a  ()  subshell,  it
        expands  to  the  process  ID of the current shell, not the sub-
        shell.

这个 current she ...

其实这里也没讲为什么$$一直是$0的PID,其原因就是因为subshell的fork是晚于变量替换。

论坛徽章:
0
4 [报告]
发表于 2006-11-20 12:10 |显示全部楼层
您能解释下这个情况的原因么?
    set | grep '^test2' #这里留一个悬念,set命令并不像前面一样是因为变量替换先于命令执行而导致直接取到了变量值,那么为什么set能获得当前shell中的所有变量呢?

论坛徽章:
0
5 [报告]
发表于 2006-11-20 18:07 |显示全部楼层
原帖由 Edengundam 于 2006-11-20 12:19 发表
我没有明白您的意思, 我猜你想问我上面这个的结果...为什么why, why2两个人都没有export, 但 why 可以在 ()中访问, why2却不可以????

呵,我故意说得有点含糊,因为再说就把答案说出来了 ^-^
如果set像其他命令那样fork subshell的话那么while所fork的current shell的所有未export的变量都将无法被set所fork的subshell获得(因为这里不像刚才讲得那样,由于变量替换先于subshell的fork而导致变量被提前取出来了),对么?所以我才有一问,为什么set能取得while所fork的这个current shell的所有未export的变量呢?
呵,其实,答案很简单,前面曾经说过,外部命令会fork subshell,而built-in command(内建命令)或者function(函数)都不会fork subshell,它们都是在current shell执行的。而set,恰好正是built-in command(内建命令)。
试验下
  1. type set
复制代码

^_____^

[ 本帖最后由 一梦如是 于 2006-11-20 18:09 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP