【发布时间】:2010-11-22 19:40:23
【问题描述】:
perl -e 'system ("crontab1 -l");print $?'
按预期返回 -1(程序 crontab1 不存在)
perl -e 'system ("crontab1 -l|grep blah");print $?'
返回 256。
检查第一个(或两个)程序状态的方法是什么?
【问题讨论】:
perl -e 'system ("crontab1 -l");print $?'
按预期返回 -1(程序 crontab1 不存在)
perl -e 'system ("crontab1 -l|grep blah");print $?'
返回 256。
检查第一个(或两个)程序状态的方法是什么?
【问题讨论】:
您将获得整个命令的退出状态,正如您应该做的那样。如果您想要单独的退出状态,您将不得不单独运行这些命令。
#!/usr/bin/perl -e
system("crontab1 -l > /tmp/junk.txt"); print $?;
system("grep blah /tmp/junk.txt"); print $?;
举个例子。
【讨论】:
如果您容忍使用 system 以外的其他内容,则有更简单的解决方案。例如the results method in IPC::Run返回链的所有退出码。
【讨论】:
记住,你应该使用 $?>>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 在这种情况下仍应为非零。
【讨论】:
((int)-1 & 0377)(这是 exit() 将返回值转换为的内容)是 0xff,或 255
[这是作为对另一个 question 的回答而编写的,该 question 已作为此邮件的副本关闭。]
执行 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::Run does]。
【讨论】:
IPC::Open3 模块中的 open3 函数,但在代码中您使用的是经典的 open 函数。
open 确实被使用了,但open3 也是如此
如果要检查状态,请不要将它们全部放在同一个系统中。打开一个到第一个程序的读取管道以获取其输出,然后打开另一个管道到另一个程序。
【讨论】:
操作系统只为最后执行的程序返回退出状态,如果操作系统不返回,perl 无法报告。
除了单独运行每个程序并使用临时文件而不是管道之外,我不知道有任何方法可以获取管道中早期程序返回的退出代码。
【讨论】:
检查第一个(或两个)程序状态的方法是什么?
没有这样的方法,至少,不是像你构建的那样。如果你必须知道这些事情,你可能必须自己通过 fork()、exec() 和 waitpid() 来管理子进程。
以下是您的代码片段中发生的大致情况。
perl 的 system() 生成一个 shell,perl *wait()*s 让该子进程终止。
shell 设置管道:
grep
$PATH 中的任何位置找到crontab1,并且*exit()*s 127(在我的系统上,即127 是表示找不到要运行的程序的shell)。李>
grep 在其输入中检测到文件结尾,并且没有匹配任何内容,*exit()*s 1。
shell *exit()*s 带有管道中最后一个进程的退出代码,同样是 1。
perl 检测到 shell 的退出代码 1,在 $? 中编码为 256。
(256 >> 8 == 1)
【讨论】: