管道命令输出,但保留错误代码

时间:2012-01-12 10:18:50

标签: shell unix sh

在我通过另一个成功的命令传送后,如何从unix命令行应用程序中获取正确的返回码?

详细说明,情况如下:

$ tar -cEvhf - -I ${sh_tar_inputlist} | gzip -5 -c > ${sh_tar_file}  --  when only the tar command fails $?=0
$ echo $?
0

而且,我希望看到的是:

$ tar -cEvhf - -I ${sh_tar_inputlist} 2>${sh_tar_error_file} | gzip -5 -c > ${sh_tar_file}
$ echo $?
1

有谁知道如何做到这一点?

4 个答案:

答案 0 :(得分:10)

使用${PIPESTATUS[0]}获取管道中第一个命令的退出状态。

有关详细信息,请参阅http://tldp.org/LDP/abs/html/internalvariables.html#PIPESTATUSREF

如果您的shell不支持$PIPESTATUS,请参阅http://cfajohnson.com/shell/cus-faq-2.html了解其他方法。

答案 1 :(得分:4)

查看$PIPESTATUS这是一个包含退出状态的数组变量。因此${PIPESTATUS[0]}保存管道中第一个命令的退出状态,${PIPESTATUS[1]}保存第二个命令的退出状态,依此类推。

例如:

$ tar -cEvhf - -I ${sh_tar_inputlist} | gzip -5 -c > ${sh_tar_file}
$ echo ${PIPESTATUS[0]}

要打印出所有状态,请使用:

$ echo ${PIPESTATUS[@]}

答案 2 :(得分:4)

以下是仅使用POSIX shell而不使用临时文件的一般解决方案:

从管道开始: foo |吧|巴兹

exec 4>&1
error_statuses=`((foo || echo "0:$?" >&3) |
        (bar || echo "1:$?" >&3) | 
        (baz || echo "2:$?" >&3)) 3>&1 >&4`
exec 4>&-

$ error_statuses包含任意失败进程的状态代码,按随机顺序排列,索引告诉每个状态发出哪个命令。

# if "bar" failed, output its status:
echo $error_statuses | grep '1:' | cut -d: -f2

# test if all commands succeeded:
test -z "$error_statuses"

# test if the last command succeeded:
echo $error_statuses | grep '2:' >/dev/null

答案 3 :(得分:1)

正如其他人所指出的,一些现代的shell提供了PIPESTATUS来获取这些信息。在经典的sh中,它有点困难,你需要使用fifo:

#!/bin/sh

trap 'rm -rf $TMPDIR' 0
TMPDIR=$( mktemp -d )
mkfifo ${FIFO=$TMPDIR/fifo}

cmd1 > $FIFO &
cmd2 < $FIFO
wait $!
echo The return value of cmd1 is $?

(好吧,你不需要使用fifo。你可以让管道中的早期命令回显一个状态变量并在主shell中评估,将文件描述符重定向到整个地方并且基本上向后弯曲到检查一下,但使用fifo会更容易。)