`
阿尔萨斯
  • 浏览: 4200879 次
社区版块
存档分类
最新评论

[Perl]管道、进程及其他

 
阅读更多
版权声明:可以任意转载,但转载时必须标明原作者charlee、原始链接http://tech.idv2.com/2008/09/04/perl-pipe-process-etc/以及本声明。


昨天一个同事问我关于Perl中的 -| 描述符的问题。他的程序大概是这样的:

unless (open FH, "-|") {
exec "foo bar"; # 用exec执行另一个程序
exit;
}
while (<FH>) {
...
}
close FH;
$ret = $? >> 8;
if ($ret == 1) {
...
}那么这里的 open FH, "-|" 是什么意思?$? >> 8 又是什么意思?

关于管道和子进程

首先看看 perldoc -f open,有这样一段话:

If you open a pipe on the command '-', i.e., either '|-' or '-|' with 2-arguments (or 1-argument) form of open(), then there is an implicit fork done, and the return value of open is the pid of the child within the parent process, and 0 within the child process. (Use "defined($pid)" to determine whether the open was successful.) The filehandle behaves normally for the parent, but i/o to that filehandle is piped from/to the STDOUT/STDIN of the child process. In the child process the filehandle isn't opened--i/o happens from/to the new STDOUT or STDIN.

这段话的意思是:如果在'-'上打开一个管道,即通过'|-'或者'-|'并带有两个参数(或一个参数)的形式执行open(),那么就会隐含地执行fork。在父进程中,open的返回值是子进程的pid,而在子进程中open的返回值是0.(使用"defined($pid)"来判断执行是否成功。)对于父进程来说,文件句柄就是普通的文件句柄,但这个文件句柄的输入输出被连接到子进程的STDOUT/STDIN上。在子进程中并不会打开这个文件句柄,输入输出只能在STDOUT或STDIN上发生。

可见,open FH, "-|"一行产生了两个进程。在子进程中open的返回值为0,因此执行下面的 exec "foo bar"语句。注意exec函数执行外部命令后不会返回,而是直接结束进程,所以子进程就到exit之前为止。不过子进程的STDIN/STDOUT被连接到了文件句柄FH上,因此foo bar命令的输出可以在父进程中通过FH来读取。

unless块之后的语句是父进程执行的,通过<FH>读取子进程产生的输出内容。

关于退出状态

那么 $? >> 8 又是什么意思?这个就说来话长了。首先看看 perldoc -f close :

Closing a pipe also waits for the process executing on the pipe to complete, in case you want to look at the output of the pipe afterwards, and implicitly puts the exit status value of that command into $?.

大意是说:关闭管道会等待管道另一端的进程执行结束,并隐含地将这个命令结束时的状态值保存到 $? 中。而现在,FH的另一端是子进程,所以close它会隐含地执行wait,然后将子进程的结束状态保存到 $? 中。 perldoc -f wait中的一句话可以验证这一点:

The status is returned in $?.

那么,$?中保存的“状态”到底是什么呢?我们知道Perl中的wait函数其实是调用系统的 wait() 或waitpid()函数。来看看wait()的文档,man 2 wait:

pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);可以推测,$? 中保存的值就是这里的 status 值。继续往下看:

If status is not NULL, wait() and waitpid() store status information in the int to which it points. This integer can be inspected with the following macros.

WEXITSTATUS(status): returns the exit status of the child.

如果status不为NULL,wait()和waitpid()将把状态信息保存到status指针指向的整数。该整数可以用下面的宏来查看:

WEXITSTATUS(status):返回子进程的退出状态。

可见,对status(在Perl中就是 $?)使用 WEXITSTATUS宏,才能得到子进程真正的退出状态(即子进程中通过exit()函数或在main()中return时设置的返回值)。

而这个WEXITSTATUS在 /usr/include/bits/waitstatus.h 中有定义:

/* If WIFEXITED(STATUS), the low-order 8 bits of the status. */
#define __WEXITSTATUS(status) (((status) & 0xff00) >> 8)/usr/include/stdlib.h 中再次封装:

# define WEXITSTATUS(status) __WEXITSTATUS(__WAIT_INT(status))可见,WEXITSTATUS宏正是在取 status 值的高8位。

到此可以得知, $? >> 8 其实是在获取子进程的退出状态。

总结

可见,上面这个例子是在Perl中执行外部程序,并获取其输出内容的一个好办法。基本的结构再次重复一下:

unless (open FH, "-|") {
# 这里是子进程的部分
exec "command"; # 通过exec命令执行外部程序
exit; # 保证子进程退出
}
while (<FH>) ... # 读取子进程命令的输出结果
close FH;
$ret = $? >> 8; # 取得子进程的返回值

分享到:
评论

相关推荐

    Network Programming With Perl

    第2章 进程、管道和信号 第3章 Berkeley套接字简介 第4章 TCP协议 第5章 IO:: Socket API 第2部分为公共服务开发客户 第6章 FTP和Telnet 第7章 SMTP:发送邮件 第8章 POP,IMAP和NNTP:处理邮件和网络新闻 ...

    Perl 实例精解(第三版).pdf

    原书名: Perl by Example(Third Edition),原出版社: PH PTR,作者: Ellie Quigley,译者: 杜炜,出版社:清华大学出版社,出版日期:2002 年8月,PDF 格式,大小 19 Mb。 内容简介 本书以最新版本的Perl ...

    Perl5语言全教程

    六、打开管道 第六章 模式匹配 一、简介 二、匹配操作符 三、模式中的特殊字符 1、字符 + 2、字符 []和[^] 3、字符 *和? 4、转义字符 5、匹配任意字母或数字 6、锚模式 7、模式中的变量替换 8、字符范围...

    perl 程序开发教程

    六、打开管道 第六章 模式匹配 一、简介 二、匹配操作符 三、模式中的特殊字符 1、字符 + 2、字符 []和[^] 3、字符 *和? 4、转义字符 5、匹配任意字母或数字 6、锚模式 7、模式中的变量替换 8、字符范围...

    Perl高级教程人称“大骆驼”(免费)

    第一章 Perl概述............................................................................................................................10 1.1 从头开始.................................................

    unix平台下c语言高级编程指南

    3.4 进程间使用管道通信 第4章 信号 4.1 信号的基本概念 4.2 信号机制 4.3 有关信号的系统调用 第5章 部分其他调用 5.1 系统调用 .5.2 相关函数 第二部分 网络编程 第6章 Socket编程基础 6.1 TCP/IP基础...

    redhat linux教材20课程学习文档

    3.6.1 管道和重定向(“|、&gt;、&gt;&gt;、&lt;”) 3.6.2 进程管理(fg/bg、ctrl-Z、 &、nohup) 3.6.3 模式匹配 3.6.4 特殊字符 3.7 环境变量 3.7.1 环境变量的概念 3.7.2 相关的命令 第四章 vi使用 4.1 vi 编辑器简介 4.1.1 ...

    websocketd:将所有使用STDINSTDOUT的程序转换为WebSocket服务器。 类似于inetd,但适用于WebSockets

    网络套接字websocketd是一个小型命令行工具,它将包装现有的命令行界面程序,并允许通过WebSocket访问它。 支持WebSocket的应用... 从WebSocket客户端发送的任何消息都将通过管道传递到进程的STDIN流,后跟\n换行符。

    CMD 编程调试命令增强版 JP Software CMDebug 25.00.26 + x64.zip

    有多种类型的 I/O 重定向,包括重定向和管道传输到 STDERR,“处理中”管道,“ here-document”和“ here-string”重定向以及 Tee 和 Y 管道配件。 将击键发送到任何应用程序(控制台或 GUI) 。 TCC-RT 包含用于 ...

    blazing-speed:适用于 Mac 和 Linux 的快速 SSHnetcat 下载器

    Blazing Speed 是一个多进程下载器,它使用SSH和netcat通过分离在不同进程中的多个管道下载单个文件。免责声明Blazing Speed 使用来工作。 如果您不想 ping 本网站,请使用‑‑own‑address参数。用法命令的语法是...

    RED HAT LINUX 6大全

    11.5.3 DNS将名字映射到IP地址及反 序操作 207 11.5.4 前区和反区必须保持同步 207 11.5.5 HUP信号和重启 207 11.5.6 IN-ADDR.ARPA域 207 11.5.7 主机命名方案 208 11.5.8 配置DNS客户:/etc/resolv.conf 208 ...

    Linux高级bash编程

    在Perl脚本中使用eval命令来强制变量替换 11-15. 使用set来改变脚本的位置参数 11-16. 重新分配位置参数 11-17. Unset一个变量 11-18. 使用export命令传递一个变量到一个内嵌awk的脚本中 11-19. 使用getopts命令来...

    Advanced Bash-Scripting Guide <>

    7.3. 其他比较操作 7.4. 嵌套的if/then 条件test 7.5. 检查你的test 知识 8. 操作符和相关的主题 8.1. 操作符 8.2. 数字常量 第三部分. 超越基本 9. 变量重游 9.1. 内部变量 9.2. 操作字符串 9.3. 参数替换 9.4. ...

    PHP基础教程 是一个比较有价值的PHP新手教程!

    CGI程序的伸缩性不很理想,因为它为每一个正在运行的CGI程序开一个独立进程。解决方法就是将经常用来编写CGI程序的语言的解释器编译进你的web服务器(比如mod_perl,JSP)。PHP就可以以这种方式安装,虽然很少有人愿意...

    2009 达内Unix学习笔记

    数字表示权限时,各数位分别表示属主、属组及其他人; 其中,1是执行权(Execute),2是写权限(Write),4是读权限(Read), 具体权限相当于三种权限的数相加,如7=1+2+4,即拥有读写和执行权。 另外,临时文件/目录...

Global site tag (gtag.js) - Google Analytics