我想在Bash中执行一个长时间运行的命令,并捕获它的退出状态,并输出它的输出。
所以我这样做:
command | tee out.txt
ST=$?
问题是变量ST捕获tee的退出状态,而不是命令的退出状态。我怎么解决这个问题?
注意,该命令长时间运行,将输出重定向到文件以供以后查看,这对我来说不是一个好的解决方案。
我想在Bash中执行一个长时间运行的命令,并捕获它的退出状态,并输出它的输出。
所以我这样做:
command | tee out.txt
ST=$?
问题是变量ST捕获tee的退出状态,而不是命令的退出状态。我怎么解决这个问题?
注意,该命令长时间运行,将输出重定向到文件以供以后查看,这对我来说不是一个好的解决方案。
当前回答
有一个内部Bash变量叫做$PIPESTATUS;它是一个数组,保存最后一个前台命令管道中每个命令的退出状态。
<command> | tee out.txt ; test ${PIPESTATUS[0]} -eq 0
或者另一种也适用于其他shell(如zsh)的选择是启用pipefail:
set -o pipefail
...
由于语法略有不同,第一个选项不能用于zsh。
其他回答
在Ubuntu和Debian中,你可以apt-get install moreutils。这包含一个名为mispipe的实用程序,它返回管道中第一个命令的退出状态。
基于@brian-s-wilson的回答;这个bash helper函数:
pipestatus() {
local S=("${PIPESTATUS[@]}")
if test -n "$*"
then test "$*" = "${S[*]}"
else ! [[ "${S[@]}" =~ [^0\ ] ]]
fi
}
使用:
1: get_bad_things必须成功,但它不应该产生输出;但我们希望看到它确实产生的输出
get_bad_things | grep '^'
pipeinfo 0 1 || return
2:所有管道必须成功
thing | something -q | thingy
pipeinfo || return
(command | tee out.txt; exit ${PIPESTATUS[0]})
与@cODAR的回答不同,它返回第一个命令的原始退出码,不仅成功为0,失败为127。但是正如@Chaoran指出的,你可以直接调用${PIPESTATUS[0]}。但重要的是,所有的都放在括号里。
愚蠢的解决方案:通过命名管道(mkfifo)连接它们。然后可以再次执行该命令。
mkfifo pipe
tee out.txt < pipe &
command > pipe
echo $?
有一个数组为您提供管道中每个命令的退出状态。
$ cat x| sed 's///'
cat: x: No such file or directory
$ echo $?
0
$ cat x| sed 's///'
cat: x: No such file or directory
$ echo ${PIPESTATUS[*]}
1 0
$ touch x
$ cat x| sed 's'
sed: 1: "s": substitute pattern can not be delimited by newline or backslash
$ echo ${PIPESTATUS[*]}
0 1