Reputation: 3606
I've got a PHP script that calls the system shell with a piped command. In this case we're talking about a backup script (but it could be anything, I'm asking specifically about the exit status!):
exec(
"mysqldump --user=$u --password=$p --host=$h --port=$p $db | gzip -9 > backup.sql.gz",
$out,
$status
);
Now I want to know if the mysqldump command yielded an error, but the $status
variable always seems to contain 0
, even if I force an error. It appears to be the exit code of the second command (gzip in this case). I want to be able to see the exit status of the first command in PHP.
Upvotes: 1
Views: 743
Reputation: 3606
I've managed to think of a more generic solution that makes the exit status of each command in the pipe available to PHP. Of course it requires a shell with $PIPESTATUS
(this excludes plain sh
).
// 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",
// ],
// ]
Slightly simpler variant if you're sure the piped commands will end with a newline (notice the echo
part in the command is different):
// 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",
// ],
// ]
Upvotes: 0
Reputation: 2679
You'll need a little help from the Bash internal array PIPESTATUS
. This holds the exit status of each command in the pipe. Since you're looking for the first command's exit status you would be addressing PIPESTATUS[0]
. So you're code would look like:
exec(
"bash -c 'mysqldump --user=$u --password=$p --host=$h --port=$p $db | gzip -9 > backup.sql.gz; exit \${PIPESTATUS[0]}'",
$out,
$status
);
Note, this changes the overall exit status of the exec()
call and you'll need additional code if you want to catch a failure in a longer chain of commands.
Upvotes: 3