免费注册 查看新帖 |

Chinaunix

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

管道 无法改变变量值 的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-09-09 11:20 |只看该作者 |倒序浏览
wqfhenanxc@ubuntu:~$ cat test.sh
#!/bin/bash
Lines=0
cat $0 | while read line
do
  ((Lines++))
done
echo "Number of lines read is: $Lines"
exit 0
wqfhenanxc@ubuntu:~$ ./test.sh
Number of lines read is: 0

wqfhenanxc@ubuntu:~$ cat test.sh
#!/bin/bash
Lines=0
while read line
do
  ((Lines++))
done <$0
echo "Number of lines read is: $Lines"
exit 0
wqfhenanxc@ubuntu:~$ ./test.sh
Number of lines read is: 8

上面两个脚本一个使用了管道来读文件,一个使用了重定向来读。
结果为什么不一样呢?
请大家从脚本执行的本质上来给一下解答。

背景知识:
1.当我在命令行中输入./test.sh时,当前shell创建子shell。
   子shell读取test.sh中的命令,对于每一行命令,都先调用fork再调用exec。

2.对于管道,子shell先创建管道描述符,然后再fork出管道两边的两个子进程,让后将一个子进程的输出重定向给另一个子进程的输入。

论坛徽章:
16
IT运维版块每日发帖之星
日期:2015-08-24 06:20:00综合交流区版块每日发帖之星
日期:2015-10-14 06:20:00IT运维版块每日发帖之星
日期:2015-10-25 06:20:00IT运维版块每日发帖之星
日期:2015-11-06 06:20:00IT运维版块每日发帖之星
日期:2015-12-10 06:20:00平安夜徽章
日期:2015-12-26 00:06:302016猴年福章徽章
日期:2016-02-18 15:30:34IT运维版块每日发帖之星
日期:2016-04-15 06:20:00IT运维版块每日发帖之星
日期:2016-05-21 06:20:00综合交流区版块每日发帖之星
日期:2016-08-16 06:20:002015七夕节徽章
日期:2015-08-21 11:06:17IT运维版块每日发帖之星
日期:2015-08-14 06:20:00
2 [报告]
发表于 2010-09-09 11:29 |只看该作者
这个问题我一直没太明白,我一般都把信息存到一个tmp的文本里,变通,不用这个子shell.
貌似要用文件描述符吧。我不懂。

论坛徽章:
5
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:50:282015年亚洲杯之朝鲜
日期:2015-03-13 22:47:33IT运维版块每日发帖之星
日期:2016-01-09 06:20:00IT运维版块每周发帖之星
日期:2016-03-07 16:27:44
3 [报告]
发表于 2010-09-09 11:33 |只看该作者
回复 1# wqfhenanxc


    bash:
  脚本在一个shell(父shell)中运行,而管道中每个命令却在子shell中运行。

论坛徽章:
33
ChinaUnix元老
日期:2015-02-02 08:55:39CU十四周年纪念徽章
日期:2019-08-20 08:30:3720周年集字徽章-周	
日期:2020-10-28 14:13:3020周年集字徽章-20	
日期:2020-10-28 14:04:3019周年集字徽章-CU
日期:2019-09-08 23:26:2519周年集字徽章-19
日期:2019-08-27 13:31:262016科比退役纪念章
日期:2022-04-24 14:33:24
4 [报告]
发表于 2010-09-09 11:47 |只看该作者
当我在命令行中输入./test.sh时,当前shell创建子shell,子shell看见有管道,于是创建孙shell

论坛徽章:
0
5 [报告]
发表于 2010-09-09 11:49 |只看该作者
回复 1# wqfhenanxc


第一个里面的Lines在子shell中,因此没有改变。ABS里面建议使用第二种方式。

论坛徽章:
0
6 [报告]
发表于 2010-09-09 11:54 |只看该作者
回复 4# Shell_HAT


    这个解释很通俗易懂啊   父 - 子 - 孙

论坛徽章:
0
7 [报告]
发表于 2010-09-09 12:03 |只看该作者
首先要搞清楚,在linux底下命令是如何执行的,然后搞清楚父进程和子进程的关系,这两个搞明白了,这个就不是问题了

论坛徽章:
0
8 [报告]
发表于 2010-09-09 14:05 |只看该作者
回复 4# Shell_HAT

下面是我的理解,不知道对不对:
脚本 中的 内建命令都是直接在子shell中执行的,
而脚本中的非内建命令是由子shell fork出一个孙shell来执行的,
但是对于管道,不管是不是内建命令,都是在孙shell中执行的,

while read line
do
((Lines++))
done < $0
这一段是内建命令,是在子shell中执行的,故其改变了子shell中Lines变量的值。

cat $0 | while read line
do
((Lines++))
done
这一段是在孙shell中执行的,并不能改变子shell中Lines变量的值。

论坛徽章:
16
IT运维版块每日发帖之星
日期:2015-08-24 06:20:00综合交流区版块每日发帖之星
日期:2015-10-14 06:20:00IT运维版块每日发帖之星
日期:2015-10-25 06:20:00IT运维版块每日发帖之星
日期:2015-11-06 06:20:00IT运维版块每日发帖之星
日期:2015-12-10 06:20:00平安夜徽章
日期:2015-12-26 00:06:302016猴年福章徽章
日期:2016-02-18 15:30:34IT运维版块每日发帖之星
日期:2016-04-15 06:20:00IT运维版块每日发帖之星
日期:2016-05-21 06:20:00综合交流区版块每日发帖之星
日期:2016-08-16 06:20:002015七夕节徽章
日期:2015-08-21 11:06:17IT运维版块每日发帖之星
日期:2015-08-14 06:20:00
9 [报告]
发表于 2010-09-09 15:24 |只看该作者
回复 8# wqfhenanxc


    呵呵,这个解释应该很靠谱,MARK

论坛徽章:
0
10 [报告]
发表于 2018-01-31 19:28 |只看该作者
本帖最后由 maxh666_cn 于 2018-01-31 19:36 编辑

今天在linux下遇到这个奇怪的问题,百思不得其解,后来发现是while循环的问题,网上一搜果然如此,但是在IBM的Aix和HPUX下都没有这个问题,这里记录一下,供参考。可能是各厂商的内部实现机制不同导致的。
# uname
AIX
# oslevel -s
5300-12-02-1036
# cat z.sh
Lines=0
cat $0 | while read line
do
  ((Lines=Lines+1))
done
echo "Number of lines read is: $Lines"
exit 0

#
#
# ./z.sh
Number of lines read is: 8
#
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP