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

Shell 管道命令输出,但保留错误代码,shell,unix,sh,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_ta

在通过另一个成功的命令将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

有人知道如何做到这一点吗?

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

例如:

$ tar -cEvhf - -I ${sh_tar_inputlist} | gzip -5 -c > ${sh_tar_file}
$ echo ${PIPESTATUS[0]}
要打印所有状态,请使用:

$ echo ${PIPESTATUS[@]}

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

有关详细信息,请参阅


如果您的shell不支持
$PIPESTATUS

,请参阅其他方法。正如其他人所指出的,一些现代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 $? #!/垃圾箱/垃圾箱 陷阱“rm-rf$TMPDIR”0 TMPDIR=$(mktemp-d) mkfifo${FIFO=$TMPDIR/FIFO} cmd1>先进先出& cmd2<$FIFO 等等! 回显cmd1的返回值为$?
(好吧,你不需要使用fifo。你可以让命令在管道的早期回显一个状态变量,并在主shell中对其进行求值,将文件描述符重定向到所有地方,基本上是向后弯曲来检查东西,但使用fifo要容易得多。)

这里是一个只使用POSIX shell而不使用临时文件的通用解决方案:

从管道开始: 福巴

exec 4>&1
error_statuses=`((foo || echo "0:$?" >&3) |
        (bar || echo "1:$?" >&3) | 
        (baz || echo "2:$?" >&3)) 3>&1 >&4`
exec 4>&-
$error_status包含任何失败进程的状态代码,以随机顺序排列,并带有索引,以指示每个状态发出的命令

# 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

$?
保存错误代码。您可以将其保存在变量中。我需要保存中间命令的返回代码,而不是最后一个命令的返回代码。Thx,但我的脚本不使用bash。我和#一起工作/垃圾箱/sh@dogbane,在
${PIPESTATUS[*]}
${PIPESTATUS[@]}
之间有什么区别吗?我总是使用前一个…Downvoted,$PIPESTATUS在POSIX中不存在。对于zsh来说,
${PIPESTATUS[1]}
似乎是第一个命令的代码所在。您好,我尝试过这种技术,但它不起作用:我测试过:/usr/bin/tar-cMEvhf--I/tmp/test.tmp>$FIFO&gzip-5-c<$FIFO>/tmp/test.bkz wait$!回显cmd1的返回值为$?即使cmd1失败,POSIX中也不存在$?=0Downvoted$管道状态。