Get exit code of a piped background process

自古美人都是妖i 提交于 2019-12-11 05:01:27

问题


someCommand 2>&1 | grep pattern &

How do I get the exit status of someCommand?

PIPESTATUS doesn't work because it's a background process.

I've found this link and it seems to work but only if I use it exactly that way. Simple echoing to the screen doesn't seem to work. I was wondering if it's possible to get the exit code without creating temporary files.


回答1:


In bash you could do :

echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"

Example :

$ ls -l | grep somefile
-rw-rw-r--  1 me me     32 May  4 15:47 somefile
$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
0 0

$ ls -l 1>/dev/null | grep while
$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
0 1

For piped foreground processes

In case of a script say testscript.sh which contains :

#!/bin/bash
echo "Some Stuff"
exit 29 # Some random exit code for testing

do

$./testscript.sh | grep somestuff
$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
29 1

For piped background processes

Method 1: Using pipefail

For testscript.sh which contains :

#!/bin/bash
set -eo pipefail  
#set -o pipefail causes a pipeline to produce a failure return code
#If a command fails, set -e will make the whole script exit,
cat nonexistingfile # this command fails
echo "Some Stuff"
exit 29

Do

$ ./testscript.sh 2>/dev/null | grep Some &
[2] 7684
$ fg 2
bash: fg: job has terminated
[2]-  Exit 1         ./testscript.sh 2> /dev/null | grep --color=auto Some

You get an the exit status 1 from which you conclude that the script failed.

Had cat nonexistingfile been removed you would have got:

[2]-  Done                    ./37257668.sh 2> /dev/null | grep --color=auto Some

Disdvantage : pipefail will return a one for all exit code that is not specific to the command that failed

Method 2 : Source the shell script

$ . ./testscript.sh 2>/dev/null | grep Some & #mind the dot in the beginning
$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
29 0

Final Touch

If you suspect a single command to fail in a shell script,test script, you could do below :

#no shebang
echo "Some Stuff"
ls non_existent 2>/dev/null || ls__return_value=50 

Do

$. ./testscript | grep "Some"

$if [ $ls__return_value -eq 50 ]; then echo "Error in ls"; fi



回答2:


With a temp file

You can put the code that saves the content of PIPESTATUS in a temp file inside { ... } and run it in background. This approach would be needed if we are interested in the exit code of more than one command in the pipeline:

{ 
  someCommand 2>&1 | grep -- pattern
  printf "0=%s\n1=%s\n" "${PIPESTATUS[0]}" "${PIPESTATUS[1]}" > status.out
} &
wait "$!"
# grab the exit code from status.out file

Without a temp file

{ 
  someCommand 2>&1 | grep -- pattern
  exit ${PIPESTATUS[0]}
} &
wait "$!"
echo $?   # this is the exit code of someCommand

wait: wait [n]

Wait for the specified process and report its termination status.  If
N is not given, all currently active child processes are waited for,
and the return code is zero.  N may be a process ID or a job
specification; if a job spec is given, all processes in the job's
pipeline are waited for.


来源:https://stackoverflow.com/questions/37257668/get-exit-code-of-a-piped-background-process

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!