Geo
Geo

Reputation: 96827

How is this bash snippet working?

A usual check if a binary exists:

if hash gdate 2>/dev/null; then
    gdate "$@"
else
    date "$@"
fi

When ran from the commandline:

vagrant@vagrant-ubuntu-saucy-32:~$ hash gdate 2>/dev/null
vagrant@vagrant-ubuntu-saucy-32:~$ echo $?
1

This means that if I run the script, date will be called since I don't have gdate on my system.

So, this would mean that the snippet above is something like this?

if 1; then
  gdate "$@"
else
  date "$@"
fi

I thought that 1 evaluates to true in bash, so, shouldn't the if branch be chosen, instead of the else? Could someone break down this snippet for me?

Upvotes: 2

Views: 100

Answers (3)

bishop
bishop

Reputation: 39414

The code works as you've analyzed. Only issue is your last statement. In bash, true ("success") is a zero exit status, non-true ("failure") is non-zero. See http://tldp.org/LDP/abs/html/exit-status.html

So, in bash, if a command exits with zero, conditionals will see that as the "true" branch. If a command exits with anything other than zero, conditionals will treat that as the "false" branch.

Upvotes: 2

Jonathan Leffler
Jonathan Leffler

Reputation: 753805

In Unix systems, an exit status of 0 is success; anything else is failure.

This is independent of what goes on inside test operations. The test command too returns (exits with a status of) 0 when the condition is true and 1 when it is false.


Comments and Answers

pfnuesel asked:

Is this always true? Isn't there C-like evaluation of true/false in some specific cases?

Specify a counter-example...Yes, I believe it is always true. Run [ "$var" != "value" ]; echo $? or [[ $var != value ]]; echo $? or similar command combinations and see what you get.

i=0; (( i++ )); echo $?

Hmmm...interesting; that definitely made me pause for thought. It complicates things, but (assuming you agree that it produces 1 from echo $?), I think that means that the (( command is being careful to invert the logic. If you run a test on the (( command for various values of $i, you will find that when the expression evaluates to 0 (as it does in your example because it is a post-increment), then the exit status is 1, which is false, but otherwise, the exit status is 0, which is true. This applies to bash and ksh (and I think that is bash following ksh).

I used this script to help clarify things to myself:

for start in {-3..3}
do
    for shell in bash ksh sh
    do
        output=$($shell -c "i=$start;"' if (( i++ )); then echo $? true $i; else echo $? false $i; fi')
        printf "%-4s %4s %s %-5s %s\n" $shell "[$start]" $output
    done
done

Output:

bash [-3] 0 true  -2
ksh  [-3] 0 true  -2
sh   [-3] 0 true  -2
bash [-2] 0 true  -1
ksh  [-2] 0 true  -1
sh   [-2] 0 true  -1
bash [-1] 0 true  0
ksh  [-1] 0 true  0
sh   [-1] 0 true  0
bash  [0] 1 false 1
ksh   [0] 1 false 1
sh    [0] 1 false 1
bash  [1] 0 true  2
ksh   [1] 0 true  2
sh    [1] 0 true  2
bash  [2] 0 true  3
ksh   [2] 0 true  3
sh    [2] 0 true  3
bash  [3] 0 true  4
ksh   [3] 0 true  4
sh    [3] 0 true  4

Interestingly, the POSIX shell syntax recognizes the possibility of (( as a command:

If a character sequence beginning with "((" would be parsed by the shell as an arithmetic expansion if preceded by a '$', shells which implement an extension whereby "((expression))" is evaluated as an arithmetic expression may treat the "((" as introducing as an arithmetic evaluation instead of a grouping command. A conforming application shall ensure that it separates the two leading '(' characters with white space to prevent the shell from performing an arithmetic evaluation.

Upvotes: 3

Keith Thompson
Keith Thompson

Reputation: 263267

That snippet attempts to execute 1 as a command. Since you very probably don't have a command by that name, the condition is false. if 0 ; then ... would do the same thing (unless you happen to have commands named 0 or 1).

If you want a condition that's always true, there are several options, the simplest of which is:

if : ; then
     ...
fi

or, if you prefer:

if true ; then
    ...
fi

Upvotes: 1

Related Questions