2

The following bash script prints "ERROR!" rather than "Server error response" even though wget returns 8:

#!/bin/bash

wget -q "www.google.com/unknown.html"
if [ $? -eq 0 ]
then
    echo "Fetch successful!"
elif [ $? -eq 8 ]
then
    echo "Server error response"
else
    echo "ERROR!"
fi

When the script above is run with -x, the first comparison with 0 seems to be setting the exit status to 1:

+ wget www.google.com/unknown.html
+ '[' 8 -eq 0 ']'
+ '[' 1 -eq 8 ']'
+ echo 'ERROR!'
ERROR!

I fixed this by using a variable for storing wget exit status, but I can not find any reference for the various ways in which $? is set. Bash details:

$ bash --version
GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
<http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Could someone point me to one?

akarollil
  • 435
  • 4
  • 12

2 Answers2

3

$? is explained, though very briefly, in the Special Parameters parameters section of man bash:

   ?      Expands to the exit status of the most recently  executed  fore-
          ground pipeline.

@chepner put it best in his comment:

The key thing to understand is that each [ ... ] is a separate foreground pipeline, not part of the if statement's syntax, and they are executed in order, updating $? as you go along.

If you want to use an if-else chain, then save the value of $? in a variable, and use conditions on that variable:

wget -q "www.google.com/unknown.html"
x=$?
if [ $x -eq 0 ]
then
    echo "Fetch successful!"
elif [ $x -eq 8 ]
then
    echo "Server error response"
else
    echo "ERROR!"
fi

But in this example, a case would be more practical:

wget -q "www.google.com/unknown.html"
case $? in
    0)
        echo "Fetch successful!" ;;
    8)
        echo "Server error response" ;;
    *)
        echo "ERROR!"
esac
Community
  • 1
  • 1
janos
  • 120,954
  • 29
  • 226
  • 236
  • 1
    The key thing to understand is that each `[ ... ]` is a separate foreground pipeline, not part of the `if` statement's syntax, and they are executed in order, updating `$?` as you go along. – chepner Nov 14 '16 at 21:25
  • @chepner, thanks! Is there a reference for the if condition being a 'pipeline'? Where did you learn about it? – akarollil Nov 14 '16 at 23:53
  • I used "pipeline" here because that is the wording used in the definition of `$?`. In general, the condition for an `if` statement is a *list*, which is one or more pipelines separated by `;`, `&`, `&&`, or `||`. A common case is that the condition consists of a *single* pipeline, and that pipeline consists of only a single command, such as `[`. – chepner Nov 15 '16 at 00:09
  • Thanks. I guess I can read `if [ $x -eq 0]` as `if test $x -eq 0`. That makes it more obvious. – akarollil Nov 15 '16 at 00:32
0

Try to use switch case on $? or store the $? in a variable.

Selim Ajimi
  • 344
  • 6
  • 21
  • Thanks, I know how to solve the problem (see my original question). I just wanted a man page or a reference that talks about the if conditionals being foreground pipelines of their own as @chepner says above. – akarollil Nov 14 '16 at 23:55