免费注册 查看新帖 |

Chinaunix

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

pipe 管道产生子进程,怎么处理? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-11-12 18:06 |只看该作者 |倒序浏览
近期我想做一个开源的网管监控平台,通过nagios 和 gnokii 短信通知故障。

最后在测试时,发现短信的发送脚本 echo -e " test message" | /usr/bin/gnokii --sendsms 138xxxxxxxxx 在 console下直接执行就成功了,手机马上收到了。
但通过软件后台调用这个脚本的时候,就不行了,我用ps -ef 看了一下,原来它生成了两个进程,一个父进程是

6319       1   echo -e "test message" | /usr/bin/gnokii --sendsms 138xxxxxxxxxx

子进程是

6321     6319  /usr/bin/gnokii --sendsms 138xxxxxxxxxx

这样一来,由于子进程没有标准输入,所以根本不会执行短信发送。

我用 source 脚本的办法,效果也是一样,不知有没有人有高招呢?

谢谢。

论坛徽章:
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
2 [报告]
发表于 2008-11-12 18:08 |只看该作者

回复 #1 crazydiy 的帖子

echo -e " test message" | /usr/bin/gnokii --sendsms 138xxxxxxxxx

这个也会产生子shell,管道2端的都是当前shell的子shell

论坛徽章:
0
3 [报告]
发表于 2008-11-12 18:13 |只看该作者
谢谢楼上的回复,

那我就实在搞不懂了,在console下,一点问题都没。

通过软件平台调用怎么就卡住了呢?

有没有什么好的见议?

论坛徽章:
0
4 [报告]
发表于 2008-11-12 21:48 |只看该作者
试试这个看看:

/usr/bin/gnokii < tmpfile --sendsms 138xxxxxxxxx

将要发送的内容写入tmpfile文件

论坛徽章:
0
5 [报告]
发表于 2008-11-12 22:16 |只看该作者
近期我想做一个开源的网管监控平台,通过nagios 和 gnokii 短信通知故障。

最后在测试时,发现短信的发送脚本 echo -e " test message" | /usr/bin/gnokii --sendsms 138xxxxxxxxx 在 console下直接执行就成功了,手机马上收到了。
通过软件后台调用这个脚本的时候,就不行了,我用ps -ef 看了一下,原来它生成了两个进程,一个父进程是

6319       1   echo -e "test message" | /usr/bin/gnokii --sendsms 138xxxxxxxxxx

子进程是

6321     6319  /usr/bin/gnokii --sendsms 138xxxxxxxxxx

这样一来,由于子进程没有标准输入,所以根本不会执行短信发送。

我用 source 脚本的办法,效果也是一样,不知有没有人有高招呢?

谢谢。

                                                        后台执行或异步执行
$command&
命令由一个子shell在后台执行,当前shell立即取得控制等候用户输入。后台命令和当前shell的执行是并行的,没有互相的依赖、等待关系,是异步的并行。
shell在后台执行,当前shell立即取得控制等候用户输入。后台命令和当前shell的执行是并行的,没有互相的依赖、等待关系,是异步的并行。

                                管道
$cmd1|cmd2
cmd1
cmd2并行执行,并且相互有依赖关系cmd2的标准输入来自cmd1的标准输出,二者是“同步”的。
对管道的处理不同的shell实现的方式不同。
linux环境下大多数shellbash/pdksh/ash/dash等,除了zshell例外)都将管道中所有的命令置于shell环境中执行,命令执行的结果不会影响当前的shell环境。

Kornshell的较新的版本(ksh93以后)比较特殊,管道最后一级的命令是在当前shell执行的。这是一个feature而非BUG,在POSIX标准中也是允许的。这样就使下面的命令结构成为可能:
command|readvar
由于readvar(read是一个内部命令)在当前shell中执行,var的值在当前shell就是可用的。

反之bash/pdksh/ash/dashreadvar在子shell环境中执行,var读到的值无法传递到当前shell,所以变量var无法取得期望的值。类似这样的问题在各种论坛和newsgroup中经常被问到。个人认为command|readvar的结构很清晰,并且合乎逻辑,所以认为Kornshell的这个feature很不错。可惜不是所有的shell都是这样实现的。

Kornshell对管道的处理还有一个特殊的地方,就是管道如果在后台执行的话,管道前面的命令会由最后一级的命令派生,而不是由当前shell派生出来。据说Bourne shell也有这个特点。

最特殊的是zshell,比较新的zshell实现(好像至少3.0.5以上)会在当前shell中执行管道中的每一级命令,不仅仅是最后一条。每一条命令都由当前shell派生,在后台执行时也是一样。可见在子sehll中执行管道命令并不是不得已的做法,大概是因为实现上比较方便或者这样的处理已经成为unix的传统之一吧。

总结一下,不同的shell对管道命令的处理可能不同。有的shellcommand|readvar这样的结构是可行的,但实际代码为了出于兼容性的缘故不能依赖这一点,最好能避免类似的代码。




                                把子shell中的变量传回父shell

$echo "$a" | readb
1.
使用临时文件
#insubshell
a=100
echo "$a">tmpfile
...
#inparent
read b<tmpfile

2.
使用命名管道
mkfifopipef
(...
echo "$a" > pipef
...)
read b<pipef

3.
使用coprocess(ksh)
echo"$a" |&
read-p b

4.
使用命令替换
b=`echo"$a"`

b=$(echo"$a")

5.
使用eval命令
eval`echo "b=$a"`

6.
使用heredocument
read b <<END
`echo "$a"`
END

7.
使用herestring(bash/pdksh)
read b <<<`echo"$a"`

8.
不用子shell,用.命令或source命令执行脚本。
即在当前shell环境下执行脚本,没有子shell,也就没有了子shell的烦恼。

论坛徽章:
0
6 [报告]
发表于 2008-11-12 22:17 |只看该作者
希望上面的内容对楼主有所帮助。

论坛徽章:
8
摩羯座
日期:2014-11-26 18:59:452015亚冠之浦和红钻
日期:2015-06-23 19:10:532015亚冠之西悉尼流浪者
日期:2015-08-21 08:40:5815-16赛季CBA联赛之山东
日期:2016-01-31 18:25:0515-16赛季CBA联赛之四川
日期:2016-02-16 16:08:30程序设计版块每日发帖之星
日期:2016-06-29 06:20:002017金鸡报晓
日期:2017-01-10 15:19:5615-16赛季CBA联赛之佛山
日期:2017-02-27 20:41:19
7 [报告]
发表于 2008-11-13 08:21 |只看该作者
echo -e "test message" | /usr/bin/gnokii --sendsms 138xxxxxxxxxx &>/dev/null

论坛徽章:
0
8 [报告]
发表于 2008-11-13 09:23 |只看该作者
gnokii
是不是只能从标准输入获得数据?或者他能,但没有对从管道获得数据加以判断,以便程序不会苦苦等待结束标志,而不是EOF。
-

论坛徽章:
0
9 [报告]
发表于 2008-11-13 11:06 |只看该作者
原帖由 WinnerBoy 于 2008-11-12 21:48 发表
试试这个看看:

/usr/bin/gnokii < tmpfile --sendsms 138xxxxxxxxx

将要发送的内容写入tmpfile文件

在console 下可以成功执行 /usr/bin/gnokii --sendsms 138xxxxxxxx <tmpfile

但放到后台,又是两个进程。

6800 1       /usr/bin/gnokii --sendsms 138xxxxxxxx <tmpfile

6801 6800 /usr/bin/gnokii --sendsms 138xxxxxxxx

论坛徽章:
0
10 [报告]
发表于 2008-11-13 12:12 |只看该作者

回复 #9 crazydiy 的帖子

我将脚本换成 /bin/ksh来执行,也是不行,依然产生同样的子进程,只不过杀掉进程时,好像父子进程跟没关系似的。
真是搞不明白了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP