获取第二个命令中管道中第一个命令的退出状态

获取第二个命令中管道中第一个命令的退出状态

我的问题类似于获取通过管道传输到另一个进程的退出状态,但我想获取管道中第二个命令的退出状态之内管道。

这是一个例子 -

false | echo $?

回报0而非预期1

PIPESTATUS给出之前的错误代码

false | echo $PIPESTATUS

返回0第一次,然后返回1,给出操作本身之后的结果。我的目的是创建一个像这样的函数:

debug() {
  # Eventually will be formatted as JSON
  echo "$(cat) was the result and the error code was $?"
}

(
  echo "Foo"
  false # To simulate an error
) | debug # debug should return "Foo was the result and the error code was 1"

答案1

你不能这样做,因为管道的两半执行同时地,所以右侧无法知道左侧是否成功。要执行您想要的操作,您必须先运行左侧命令,然后等待它退出。然后您可以显示命令的输出和退出代码。

您可能会发现此代码片段更适合您的目的:

myfunc() {
  echo foo
  read
}

out="$(myfunc)"
rc=$?
printf '%s was the result and the error code was %d\n' "$out" $rc

$ yes | ./test.sh 
foo was the result and the error code was 0
$ ./test.sh < /dev/null
foo was the result and the error code was 1

答案2

吉姆的回答绝对是正确的。然而,在我的特定用例中,我发现该trap命令为我提供了管道的干净语法,同时仍然捕获错误。

我最终选择了这个:

set -E

trap 'catch $? $LINENO' ERR

catch() {
    echo "{ \"type\": \"error\", \"error\": \"$1\", \"line\": \"$2\" }"
    exit $1
}

debug() {
  # Eventually will be formatted as JSON
  echo "$(cat) was the result"
}

(
  echo "Foo"
  # Simulate an error
  false
  echo "This should not be run!"
) | debug

其输出:

Foo
{ "type": "error", "error": "1", "line": "18" } was the result

如您所见,echo "This should not be run!"从未被执行!

最后,将 JSON 格式化为用 替换换行符后\n,您将得到以下结果:

{ "content": "Foo\n{ "error": "1", "line": "18" }" }

它需要一些后处理,特别是修复嵌套引号和/或将stdin输入与trap输出分开。

相关内容