我想在Bash中执行一个长时间运行的命令,并捕获它的退出状态,并输出它的输出。

所以我这样做:

command | tee out.txt
ST=$?

问题是变量ST捕获tee的退出状态,而不是命令的退出状态。我怎么解决这个问题?

注意,该命令长时间运行,将输出重定向到文件以供以后查看,这对我来说不是一个好的解决方案。


当前回答

在bash之外,您可以执行以下操作:

bash -o pipefail  -c "command1 | tee output"

这很有用,例如在ninja脚本中,shell被期望为/bin/sh。

其他回答

在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

有一个内部Bash变量叫做$PIPESTATUS;它是一个数组,保存最后一个前台命令管道中每个命令的退出状态。

<command> | tee out.txt ; test ${PIPESTATUS[0]} -eq 0

或者另一种也适用于其他shell(如zsh)的选择是启用pipefail:

set -o pipefail
...

由于语法略有不同,第一个选项不能用于zsh。

使用bash的set -o pipefail是有帮助的

Pipefail:管道的返回值是状态 最后一个以非零状态退出的命令, 如果没有命令以非零状态退出,则为零

愚蠢的解决方案:通过命名管道(mkfifo)连接它们。然后可以再次执行该命令。

 mkfifo pipe
 tee out.txt < pipe &
 command > pipe
 echo $?