处理替代代码和退出代码

时间:2018-06-27 22:02:07

标签: bash

我想在给定的时间内监视过程的输出。除了给我运行命令的返回值之外,下面的命令可以满足我的所有要求。

cmd='cat <<EOF
My
Three
Lines
EOF
exit 2
'

perl -pe "if (/Hello/) { print \$_; exit 1 }" <(echo "$cmd" | timeout 
5 bash)

有人能获得该返回值吗?我在这里查看了其他问题,但是在这种情况下,没有答案适用。

1 个答案:

答案 0 :(得分:2)

仅限Bash 4.4:使用$!收集PID,并在该PID上wait

Bash仅使收集版本4.4中的进程替换的退出状态成为可能。由于无论如何我们都需要该版本,最好也使用自动FD分配。 :)

exec {psfd}< <(echo "hello"; exit 3); procsub_pid=$!
cat <&$psfd           # read from the process substitution so it can exit
exec {psfd}<&-        # close the FD
wait "$procsub_pid"   # wait for the process to collect its exit status
echo "$?"

...正确返回:

3

在您的代码上下文中,可能类似于:

cmd() { printf '%s\n' My Three Lines; exit 2; }
export -f cmd

exec {psfd}< <(timeout 5 bash -c cmd); ps_pid=$!
perl -pe "if (/Hello/) { print \$_; exit 1 }" <&$psfd
echo "Perl exited with status $?"
wait "$ps_pid"; echo "Process substitution exited with status $?"

...作为输出发射:

Perl exited with status 0
Process substitution exited with status 2

简单答案:做其他事情

虽然可以在最近的Shell版本中解决此问题,但通常来说,进程替换会占用退出状态。更重要的是,在给出的示例中根本不需要它们。

如果设置pipefail shell选项,则管道中任何组件(不仅是最后一个组件)的退出状态都将反映在管道的退出状态中。因此,您无需使用进程替换也可以尊重perl的退出状态。

#!/usr/bin/env bash

set -o pipefail

cmd() { printf '%s\n' My Three Lines; exit 2; }
export -f cmd

timeout 5 bash -c 'cmd' | perl -pe "if (/Hello/) { print \$_; exit 1 }"
printf '%s\n' \
  "Perl exited with status ${PIPESTATUS[1]}" \
  "Process substitution exited with status ${PIPESTATUS[0]}"