16

How can I get exit code of wget from the subshell process?

So, main problem is that $? is equal 0. Where can $?=8 be founded?

$> OUT=$( wget -q "http://budueba.com/net" | tee -a "file.txt" ); echo "$?"
0

It works without tee, actually.

$> OUT=$( wget -q "http://budueba.com/net" ); echo "$?"
8

But ${PIPESTATUS} array (I'm not sure it's related to that case) also does not contain that value.

$> OUT=$( wget -q "http://budueba.com/net" | tee -a "file.txt" ); echo "${PIPESTATUS[1]}"    

$> OUT=$( wget -q "http://budueba.com/net" | tee -a "file.txt" ); echo "${PIPESTATUS[0]}"
0

$> OUT=$( wget -q "http://budueba.com/net" | tee -a "file.txt" ); echo "${PIPESTATUS[-1]}"
0

So, my question is - how can I get wget's exit code through tee and subshell?

If it could be helpful, my bash version is 4.2.20.

3 Answers3

22

By using $() you are (effectively) creating a subshell. Thus the PIPESTATUS instance you need to look at is only available inside your subshell (i.e. inside the $()), since environment variables do not propagate from child to parent processes.

You could do something like this:

  OUT=$( wget -q "http://budueba.com/net" | tee -a "file.txt"; exit ${PIPESTATUS[0]} );
  echo $? # prints exit code of wget.

You can achieve a similar behavior by using the following:

  OUT=$(wget -q "http://budueba.com/net")
  rc=$? # safe exit code for later
  echo "$OUT" | tee -a "file.txt"
Christian.K
  • 44,947
  • 10
  • 92
  • 136
  • But is it possible to export all `${PIPESTATUS}` array up to parent shell? – ДМИТРИЙ МАЛИКОВ Feb 14 '12 at 13:49
  • 2
    That is not how [`export`](http://www.gnu.org/software/bash/manual/bashref.html#Environment) works - it exports variables as environment variables for *child* processes (from the parent). – Christian.K Feb 14 '12 at 13:52
  • Here is a [solution for bringing the entire `${PIPESTATUS[@]}` array into the parent script](https://stackoverflow.com/questions/41716616/get-exit-codes-of-a-pipe-when-output-is-assigned-to-variable-command-substituti/44314883#44314883). It involves adding it to the end of the created variable and then pulling it off into a new array. – Adam Katz Jun 01 '17 at 21:10
5

Beware of this when using local variables:

local OUT=$(command; exit 1)
echo $? # 0

OUT=$(command; exit 1)
echo $? # 1
Mrskman
  • 302
  • 2
  • 10
  • 5
    Declaring `local OUT` then assigning `OUT=` on a new line correctly sets the exit code variable `$?` if you don't want scope creep. – William George Apr 05 '17 at 03:02
0

Copy the PIPESTATUS array first. Any reads destroy the current state.

declare -a PSA  
cmd1 | cmd2 | cmd3  
PSA=( "${PIPESTATUS[@]}" )

I used fifos to solve the sub-shell/PIPESTATUS problem. See bash pipestatus in backticked command?
I also found these useful: bash script: how to save return value of first command in a pipeline?
and https://unix.stackexchange.com/questions/14270/get-exit-status-of-process-thats-piped-to-another/70675#70675

Community
  • 1
  • 1
maxdev137
  • 51
  • 2