0

I want to get the return value of command run in background with pipe so i have below sample code.

#!/bin/bash

export RETVALUE="0"
CMD='ls ThisFileDoesNotExit'
LOG='tee -a log.txt'
$CMD | $LOG ; RETVALUE=${PIPESTATUS[0]} &
#$CMD | $LOG ; echo ${PIPESTATUS[0]} & // This print ret value 2
wait
echo "Return Value of ls is $RETVALUE"

Output:

Return Value of ls is 0 // It should print value 2

If i echo the return value from same command then it print correct return value.

But if store it in RETVALUE variable then it shows wrong value.

Jeegar Patel
  • 26,264
  • 51
  • 149
  • 222
  • 1
    This? [shell - get exit code of background process](http://stackoverflow.com/a/1570356/1983854). That is, `$!` – fedorqui Jul 27 '16 at 09:15
  • 1
    you are storing it into a variable already: RETVALUE. There is nothing that will keep you from assigning that variable's value to another `var=$RETVALUE` – SaintHax Jul 27 '16 at 09:18
  • @SaintHax By assigning this way, $RETVALUE always print "0" while error return value is 2. Please see updated question. – Jeegar Patel Jul 27 '16 at 09:55
  • @fedorqui $! will return the pid of forked process. I need to return value of 1st process in pipe command. And i can get that value by echo but not by storing in RETVALUE variable. – Jeegar Patel Jul 27 '16 at 09:59
  • 2
    [Don't store commands in variables.](http://mywiki.wooledge.org/BashFAQ/050) – chepner Jul 27 '16 at 12:09
  • Possible duplicate of [command to capture exit status of last background process in bash](http://stackoverflow.com/questions/20257935/command-to-capture-exit-status-of-last-background-process-in-bash) – SaintHax Jul 27 '16 at 13:39

1 Answers1

5

The problem is due to the & sign. This puts the RETVALUE assignment into the background, thus this command executes in a different environment than the current script, so the variables in your script do no get updated.

You also don't need to export the RETVALUE. Also the wait command is not necessary, as bash does not process the next command until it has finished the previous one (unless you use the & to put it in the background)

#!/bin/bash

RETVALUE="0"
CMD='ls ThisFileDoesNotExit'
LOG='tee -a log.txt'
$CMD | $LOG
RETVALUE=${PIPESTATUS[0]}
echo "Return Value of ls is $RETVALUE"

EDIT: If you need to launch the process in the background, you will be forced to create a new script in order to recover the PIPESTATUS value, due to this variable is volatile. A possible solution is:

#!/bin/bash

CMD='ls ThisFileDoesNotExit'
LOG='tee -a log.txt'
TMPSCRIPT="file1.sh"
echo '#!/bin/bash' > $TMPSCRIPT
echo "$CMD |$LOG" >> $TMPSCRIPT
echo 'exit ${PIPESTATUS[0]}' >> $TMPSCRIPT
chmod +x $TMPSCRIPT
./$TMPSCRIPT &
MYPID=$!
wait $MYPID
RETVALUE=$?
rm $TMPSCRIPT
echo "Return Value of ls is $RETVALUE"
AwkMan
  • 670
  • 6
  • 18
  • I need to run whole commnad in background only so i have put & . Without & its work fine but i need to do the same for background – Jeegar Patel Jul 27 '16 at 10:21
  • Yes man...it works as i wanted... let me look for any other solution if possible then. Otherwise i will accept your answer. – Jeegar Patel Jul 27 '16 at 11:17
  • 1
    It's simpler to wrap the command in a function that to write out a temporary script: `tmp_func () { command | tee -a log.txt; return ${PIPESTATUS[0]}; }`, then run the *function* in the background to eventually `wait` on it. – chepner Jul 27 '16 at 13:09