我想在Bash中执行一个长时间运行的命令,并捕获它的退出状态,并输出它的输出。
所以我这样做:
command | tee out.txt
ST=$?
问题是变量ST捕获tee的退出状态,而不是命令的退出状态。我怎么解决这个问题?
注意,该命令长时间运行,将输出重定向到文件以供以后查看,这对我来说不是一个好的解决方案。
我想在Bash中执行一个长时间运行的命令,并捕获它的退出状态,并输出它的输出。
所以我这样做:
command | tee out.txt
ST=$?
问题是变量ST捕获tee的退出状态,而不是命令的退出状态。我怎么解决这个问题?
注意,该命令长时间运行,将输出重定向到文件以供以后查看,这对我来说不是一个好的解决方案。
当前回答
在Ubuntu和Debian中,你可以apt-get install moreutils。这包含一个名为mispipe的实用程序,它返回管道中第一个命令的退出状态。
其他回答
通过结合PIPESTATUS[0]和在子shell中执行exit命令的结果,您可以直接访问初始命令的返回值:
命令| tee;退出${PIPESTATUS[0]}
这里有一个例子:
# the "false" shell built-in command returns 1
false | tee ; ( exit ${PIPESTATUS[0]} )
echo "return value: $?"
会给你:
返回值:1
(command | tee out.txt; exit ${PIPESTATUS[0]})
与@cODAR的回答不同,它返回第一个命令的原始退出码,不仅成功为0,失败为127。但是正如@Chaoran指出的,你可以直接调用${PIPESTATUS[0]}。但重要的是,所有的都放在括号里。
在Ubuntu和Debian中,你可以apt-get install moreutils。这包含一个名为mispipe的实用程序,它返回管道中第一个命令的退出状态。
在bash之外,您可以执行以下操作:
bash -o pipefail -c "command1 | tee output"
这很有用,例如在ninja脚本中,shell被期望为/bin/sh。
在普通bash中最简单的方法是使用进程替换而不是管道。有几个不同之处,但它们可能对你的用例不太重要:
当运行管道时,bash等待所有进程完成。 向bash发送Ctrl-C使其杀死管道的所有进程,而不仅仅是主要进程。 pipefail选项和PIPESTATUS变量与进程替换无关。 可能更
使用进程替换,bash只是启动进程,然后忘记它,它甚至在作业中都不可见。
除了上面提到的差异,消费者< <(生产者)和生产者|消费者本质上是相同的。
如果想要转换哪个进程是“主”进程,只需将命令和替换方向转换为生产者> >(消费者)。在你的情况下:
command > >(tee out.txt)
例子:
$ { echo "hello world"; false; } > >(tee out.txt)
hello world
$ echo $?
1
$ cat out.txt
hello world
$ echo "hello world" > >(tee out.txt)
hello world
$ echo $?
0
$ cat out.txt
hello world
正如我所说,它与管道表达式有不同之处。进程可能永远不会停止运行,除非它对管道关闭很敏感。特别是,它可能会不断向您的标准输出写入内容,这可能会令人困惑。