如何在Perl的system()中检查管道中第一个程序的状态?

时间:2009-08-25 22:52:41

标签: perl ipc

perl -e 'system ("crontab1 -l");print $?'

按预期返回-1(程序crontab1不存在)

perl -e 'system ("crontab1 -l|grep blah");print $?'

返回256。

检查第一个(或两个)程序状态的方法是什么?

7 个答案:

答案 0 :(得分:4)

您正在获得整个命令的退出状态,就像您应该的那样。如果您想单独退出状态,则必须单独运行命令。

#!/usr/bin/perl -e
system("crontab1 -l > /tmp/junk.txt"); print $?;
system("grep blah /tmp/junk.txt"); print $?;

作为一个例子。

答案 1 :(得分:4)

如果您容忍使用system以外的其他内容,则可以使用更简单的解决方案。例如,the results method in IPC::Run返回链的所有退出代码。

答案 2 :(得分:3)

请记住,您应该使用$?>> 8来获取退出代码,而不是$?

perl -e 'system("set -o pipefail;false | true");print $?>>8,"\n"'

1

这个(“pipefail”)只有在你的shell是bash 3时才有效.Cygwin和linux附带它;不确定mac。

您应该知道256是错误返回。 0是你获得成功的原因:

perl -e 'system("true");print $?>>8,"\n"'

0

对于未找到的单个命令,我不知道系统返回-1,但在这种情况下,$?>> 8仍应为非零。

答案 3 :(得分:2)

[这是作为另一个question的答案而作出的,该does作为此副本的副本而被关闭。]

执行shell命令需要执行shell。为此,

system($shell_command)

相当于

system('/bin/sh', '-c', $shell_command)

因此,您的所有示例都运行一个程序(/bin/sh)。如果你想要多个孩子的退出状态,你需要有多个孩子!

use IPC::Open3 qw( open3 );

open(local *CHILD1_STDIN, '<', '/dev/null')
   or die $!;

pipe(local *CHILD2_STDIN, local *CHILD1_STDOUT)
   or die $!;

my $child1_pid = open3(
   '<&CHILD1_STDIN',
   '>&CHILD1_STDOUT',
   '>&STDERR',
   'prog1', 'arg1', 'arg2',
);

my $child2_pid = open3(
   '<&CHILD2_STDIN',
   '>&STDOUT',
   '>&STDERR',
   'prog2', 'arg1', 'arg2',
);

my @pipe_status = map { waitpid($_, 0) } $child1_pid, $child2_pid;

IPC :: Open3相当低级。 IPC :: Run3和/或IPC :: Run可以使这更容易。 [更新:确实,IPC ::运行{{3}}]。

答案 4 :(得分:1)

如果要检查状态,请不要将它们全部放在同一系统中。打开第一个程序的读取管道以获取其输出,然后打开另一个管道到另一个程序。

答案 5 :(得分:1)

操作系统仅为最后执行的程序返回退出状态,如果操作系统没有返回,则perl无法报告。

我不知道如何获取管道中早期程序返回的退出代码,而不是单独运行每个程序并使用临时文件而不是管道。

答案 6 :(得分:1)

  

检查第一个(或两个)程序状态的方法是什么?

至少没有这样的方式,不是因为你已经构建了东西。如果你必须知道这些事情,你可能必须通过fork(),exec()和waitpid()自己管理子进程。

以下是您的代码片段中发生的情况。

  1. perl system()生成一个shell,perl * wait()* s为该子进程终止。

    < / LI>
  2. shell设置了一个管道:

    1. 管道读取端的子shell * exec()* s grep
    2. 子shell无法在crontab1中找到$PATH,并且* exit()* s 127(在我的系统上,也就是说,其中127是shell,表示无法找到要运行的程序) )。
  3. grep检测到其输入文件的结尾,并且没有匹配,* exit()* s 1.

  4. shell * exit()* s,其中包含管道中最后一个进程的退出代码,该代码再次为1.

  5. perl检测到shell的退出代码为1,该代码以$?编码为256。
    (256>&gt; 8 == 1)