我想在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。
其他回答
纯壳方案:
% rm -f error.flag; echo hello world \
| (cat || echo "First command failed: $?" >> error.flag) \
| (cat || echo "Second command failed: $?" >> error.flag) \
| (cat || echo "Third command failed: $?" >> error.flag) \
; test -s error.flag && (echo Some command failed: ; cat error.flag)
hello world
现在第二只猫被false取代:
% rm -f error.flag; echo hello world \
| (cat || echo "First command failed: $?" >> error.flag) \
| (false || echo "Second command failed: $?" >> error.flag) \
| (cat || echo "Third command failed: $?" >> error.flag) \
; test -s error.flag && (echo Some command failed: ; cat error.flag)
Some command failed:
Second command failed: 1
First command failed: 141
请注意,第一个cat也失败了,因为它的stdout关闭了。在本例中,日志中失败命令的顺序是正确的,但不要依赖它。
此方法允许捕获单个命令的stdout和stderr,以便在发生错误时将其转储到日志文件中,或者在没有错误时删除它(如dd的输出)。
为什么不使用stderr?像这样:
(
# Our long-running process that exits abnormally
( for i in {1..100} ; do echo ploop ; sleep 0.5 ; done ; exit 5 )
echo $? 1>&2 # We pass the exit status of our long-running process to stderr (fd 2).
) | tee ploop.out
所以ploop。Out接收标准输出。Stderr接收长时间运行的进程的退出状态。这样做的好处是完全与posix兼容。
(好吧,除了示例长时间运行的进程中的range表达式,但这并不真正相关。)
这是它的样子:
...
ploop
ploop
ploop
ploop
ploop
ploop
ploop
ploop
ploop
ploop
5
请注意,返回代码5不会输出到文件plop .out。
通过结合PIPESTATUS[0]和在子shell中执行exit命令的结果,您可以直接访问初始命令的返回值:
命令| tee;退出${PIPESTATUS[0]}
这里有一个例子:
# the "false" shell built-in command returns 1
false | tee ; ( exit ${PIPESTATUS[0]} )
echo "return value: $?"
会给你:
返回值:1
愚蠢的解决方案:通过命名管道(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