免费注册 查看新帖 |

Chinaunix

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

简简单单讲管道(仙子原创) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2005-10-03 23:14 |只看该作者 |倒序浏览
简简单单讲管道

是不是经常被perl的open pipe方式迷惑呀?是不是看到'-|','|-'这种写法就头晕?不要怕,不要怕,让仙子来告诉这一切。


(一)父进程写往子进程的管道

看看如下几句:

open(FOO, "|tr '[a-z]' '[A-Z]'");
open(FOO, '|-', "tr '[a-z]' '[A-Z]'");
open(FOO, '|-') || exec 'tr', '[a-z]', '[A-Z]';

它们是一样的吗?答案是:当然一样。

为什么?为什么?

让我们看看第一个:

open(FOO, "|tr '[a-z]' '[A-Z]'");

tr是什么?它是个unix的shell命令。它在管道右边,意味着什么?笨啊,当然意味着从管道左边接受输入啦。

如果你还不清楚,那么在shell里运行:

echo 'abcd' |tr '[a-z]' '[A-Z]'
ABCD

看到没有,你输入的abcd通过管道传给tr后,就处理成ABCD了。

那么,perl里也一样呀。open(FOO, "|tr '[a-z]' '[A-Z]'");它打开一个管道,并将数据通过句柄FOO传递给tr命令。这里有点巧妙,实际上发生了1个fork过程。tr命令实际上是在子进程里完成的啦。

对了,有人问了,这个子进程与fork出来的有何不同?主要的不同就在于子进程的STDIN被重定向到管道了,也就是说它从FOO句柄接受输入,然后它将结果输出到STDOUT,这样你在屏幕上就可见到ABCD啦。

明白了吗?很简单吧,:p 那接着看第2个:

open(FOO, '|-', "tr '[a-z]' '[A-Z]'");

这个与第1个其实一样的,只是写法不同啦!不过很多人被这个|-迷惑住了,以后再见到,就不要怕怕了哦,简单的把这个'-'想象成后面的shell命令就可以了呀。

好了,再看看第3个:

open(FOO, '|-') || exec 'tr', '[a-z]', '[A-Z]';

晕,这是什么意思啊?别着急,听偶慢慢道来。

已经说了哦,open过程中实际会发生一个fork过程,这个fork对父进程返回子进程的pid,通常是个正整数;对子进程返回0。所以:

my $pid=open(FOO,'|-');

若$pid >; 0那就表示位于父进程里啦。||是什么意思呀?||是个or运算符,它后面的条件与前面的条件相反,前面的是$pid >;0,那后面的就是$pid==0啦,这样你就明白了吧,偶已经位于子进程里了。

那exec呢?exec与system意思差不多,不同的是exec执行的命令完全替代了fork出来的子进程,除了进程号一样外,其他的代码段,堆栈段什么的都替换掉了。如果你不明白,那么翻翻仙子以前的关于exec的解释啦;什么?还不明白?那就把它想象成system()好啦。

所以这里你应该明白啦:

open(FOO, '|-') || exec 'tr', '[a-z]', '[A-Z]';

exec从管道接受数据,也就是说在子进程里,从FOO句柄接受数据,转换后再将结果写往标准输出,跟前面2个例子一样呀。

不过仙子提醒大家,上述3种情况下,你应该记住:

1)在父进程里,对FOO句柄操作的行为与正常的一致,例如,你这样将数据写入FOO句柄:

print FOO $str;

2)在子进程里,STDIN被重定向了哦。它默认从管道接受数据了。但STDOUT不变。不要混淆了哦,:-)


(二)子进程写往父进程的管道

同样的,看看如下代码:

open(FOO, "cat -n '$file'|");
open(FOO, '-|', "cat -n '$file'");
open(FOO, '-|') || exec 'cat', '-n', $file;

这把大家都聪明了,它们肯定是一样的呀。

让我们先看看第1句,它简单点哦。

open(FOO, "cat -n '$file'|");

它的意思其实与前面的差不多哦,cat执行了外部shell命令,等于是fork了一个子进程,它将输出通过管道发送给父进程。如果你还不是很理解,那么看下这个shell命令:

cat -n $file | more

明白了吗?cat的结果通过管道发送给more了。

那么这里也一样呀,cat -n '$file'的结果写往了FOO句柄,父进程正常的读取这个句柄,就可以获取到cat的输出啦。父进程里这样写就可以啦:

print my $line=<FOO>;;

好,接着看第2句:

open(FOO, '-|', "cat -n '$file'");

又是'-|',开始晕了吧?不要晕,它与第1句一样呀,写法不同罢了。记着:把'-'想象成后面的shell命令。

再看第3句哦:

open(FOO, '-|') || exec 'cat', '-n', $file;

这里与前面的一样哦,如果你理解了fork,理解了||,理解了exec,那么看它就清清楚楚啦。作用还是一样的哦,||后面的子进程将结果写往FOO句柄,父进程就从FOO句柄接受数据了。

仙子再次提醒大家,在上述3种情况下要注意:

1)父进程对FOO句柄的操作还是与正常的一致,例如,它这样接受FOO句柄的数据:
my $line=<FOO>;;

2)子进程的STDOUT被重定向了,也就是说,子进程的任何输出都会写往管道了。


好了,到这里你应该大概清楚open pipe的方式了吧?还不太明白?那么去看看perldoc的相关手册吧。

哦,还有个问题,能不能把子进程的STDIN和STDOUT同时定向到FOO句柄呀?晕,那就是双向管道了哦,仙子不太明白这方面的应用,看看IPC的相关文档吧。

论坛徽章:
1
技术图书徽章
日期:2013-12-05 23:25:45
2 [报告]
发表于 2005-10-03 23:34 |只看该作者

简简单单讲管道(仙子原创)

还是晕,不简洁明了

论坛徽章:
1
技术图书徽章
日期:2013-12-05 23:25:45
3 [报告]
发表于 2005-10-03 23:36 |只看该作者

简简单单讲管道(仙子原创)

虽然我明白你在说什么

论坛徽章:
0
4 [报告]
发表于 2005-10-04 00:36 |只看该作者

简简单单讲管道(仙子原创)

[quote]原帖由 "HonestQiao"]还是晕,不简洁明了[/quote 发表:


不能再简洁了嘛,再简单就会连偶自己也糊涂的

论坛徽章:
0
5 [报告]
发表于 2005-10-04 01:57 |只看该作者

简简单单讲管道(仙子原创)

迷迷糊糊,没有用过,等用的时候再仔细看

论坛徽章:
0
6 [报告]
发表于 2005-10-04 11:33 |只看该作者

简简单单讲管道(仙子原创)

补充一下:
使用'|-' or '-|'的好处是可以更精细的控制子进程。
考虑前面有人提到的示例:

  1. my $child=open(HD,'-|');
  2. unless ($child){
  3.     do something...;         # in child
  4. }else{
  5.     <HD>;....;                    # in parent
  6. }
复制代码


在上述例子的子进程里,你就可以做任何事了哦。
子进程将输出写往管道,父进程就可以通过<HD>;来获取数据了。
很好的进程间使用管道进行通信的例子,是不是?

论坛徽章:
1
荣誉会员
日期:2011-11-23 16:44:17
7 [报告]
发表于 2005-10-04 11:43 |只看该作者

简简单单讲管道(仙子原创)

写得很好呀...
如果有附图说明..会更容易让人了解 ..

呵呵..我好像太贪心了...

论坛徽章:
0
8 [报告]
发表于 2005-10-04 14:53 |只看该作者

简简单单讲管道(仙子原创)

原帖由 "apile" 发表:
写得很好呀...
如果有附图说明..会更容易让人了解 ..

呵呵..我好像太贪心了...


偶还不知道怎样在这里帖图呢。
不过把parent及child的I/O关系画出来,是更好点哦。

论坛徽章:
0
9 [报告]
发表于 2005-10-04 17:20 |只看该作者

简简单单讲管道(仙子原创)

支持贴图,发给偶,偶帮你贴^_^

论坛徽章:
0
10 [报告]
发表于 2005-10-13 18:26 |只看该作者

简简单单讲管道(仙子原创)

今天偶在写mod_perl code时,发现一个可怕的pipe error,but,有点复杂,偶就不在这里describe了...
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP