获取PHP中管道命令的退出状态

获取PHP中管道命令的退出状态,php,bash,Php,Bash,我有一个PHP脚本,它使用管道命令调用系统shell。在本例中,我们讨论的是一个备份脚本(但它可以是任何东西,我要特别询问退出状态!): 现在我想知道mysqldump命令是否产生错误,但是$status变量似乎总是包含0,即使我强制执行错误也是如此。它似乎是第二个命令(本例中为gzip)的退出代码。我希望能够在PHP中查看first命令的退出状态。您需要Bash内部数组PIPESTATUS的一些帮助。这将保存管道中每个命令的退出状态。由于您正在查找第一个命令的退出状态,因此您将寻址PIPEST

我有一个PHP脚本,它使用管道命令调用系统shell。在本例中,我们讨论的是一个备份脚本(但它可以是任何东西,我要特别询问退出状态!):


现在我想知道mysqldump命令是否产生错误,但是
$status
变量似乎总是包含
0
,即使我强制执行错误也是如此。它似乎是第二个命令(本例中为gzip)的退出代码。我希望能够在PHP中查看first命令的退出状态。

您需要Bash内部数组
PIPESTATUS
的一些帮助。这将保存管道中每个命令的退出状态。由于您正在查找第一个命令的退出状态,因此您将寻址
PIPESTATUS[0]
。因此,您的代码如下所示:

exec(
    "bash -c 'mysqldump --user=$u --password=$p --host=$h --port=$p $db | gzip -9 > backup.sql.gz; exit \${PIPESTATUS[0]}'",
    $out,
    $status
);

请注意,这会更改
exec()
调用的整体退出状态,如果要捕获较长命令链中的故障,则需要额外的代码

我设法想出了一个更通用的解决方案,使管道中的每个命令的退出状态可供PHP使用。当然,它需要一个带有
$PIPESTATUS
(这不包括普通
sh
)的shell

如果您确定管道命令将以换行符结尾,则该变量稍微简单一些(请注意命令中的
echo
部分有所不同):


为什么不串联执行呢?那么就很容易说了。@e4c5,这些问题到底有什么相似之处?我问的是退出状态,不是备份。示例脚本恰好是一个数据库备份脚本。@Machavity,我不想要一个大的中间文件。太好了,谢谢。这正是我要找的。剩下的只有两件事:是否有可能获得一系列退出状态?我想不会,除非您输出它们,然后将最后一行输出表示退出状态。我说得对吗?第二件事是如何使用除bash之外的shell(对我来说这不是一个困难的要求,但是如果你知道如何使用,那就很好了)。是的,你必须将exit status数组设置为“输出”,而不是exit status
PIPESTATUS
是Bash内置的,我认为zsh也有它。我不相信其他的贝壳能做到。因此,你必须寻找其他方法来实现这一点。
exec(
    "bash -c 'mysqldump --user=$u --password=$p --host=$h --port=$p $db | gzip -9 > backup.sql.gz; exit \${PIPESTATUS[0]}'",
    $out,
    $status
);
// The command with pipes.
$command = 'command1 | command2 | echo Test | gzip -9 -f';

// Execute the command. The overall exit code is in $exitStatus.
exec(
    $command . '; echo -e "\n"${PIPESTATUS[*]}',
    $out,
    $exitStatus
);

// Get the exit statuses and remove them from the output.
$pipeStatus = explode(' ', array_pop($out));

print_r([$pipeStatus, $out]);
// [
//   [
//     "127",
//     "127",
//     "0",
//     "0",
//   ],
//   [
//     b"\x1F‹\x089fÙW\x02I-.á\x02Â\x1Axú\x05",
//   ],
// ]
// The command with pipes.
$command = 'command1 | command2 | echo Testing things | sed s/things/stuff/';

// Execute the command. The overall exit code is in $exitStatus.
exec(
    $command . '; echo ${PIPESTATUS[*]}',
    $out,
    $exitStatus
);

// Get the exit statuses and remove them from the output.
$pipeStatus = explode(' ', array_pop($out));

print_r([$pipeStatus, $out]);
// [
//   [
//     "127",
//     "127",
//     "0",
//     "0",
//   ],
//   [
//     "Testing stuff",
//   ],
// ]