3

I have done some testing of the bash if statement behavior, but I am not sure whether I understand them correctly on the reason of the output.

Below are the reason I am proposing from each different if statement output, are all the reasons correct ? I also can't find out the answer of one of the behavior as stated below. bash version is 4.1.2.

#!/bin/bash

set -x

# behavior 1
if [ $anything ]; then
        echo 'true 1'
fi
# result is false cause $anything will be translated by bash to an empty string, and in 'test' command, EXPRESSION omitted will be false

# behavior 2
if [ '' ];then
        echo 'true 2'
fi
# result is false cause in 'test' command, EXPRESSION omitted will be false

# behavior 3
if [ 0 ]; then
        echo 'true 3'
fi
# result is true cause 0 is a STRING and that is same with '-n STRING', since the length of string '0' is definitely nonzero, so it is true

# behavior 4
if [ ]; then
        echo 'true 4'
fi
# result is false cause in 'test' command, EXPRESSION omitted will be false

# behavior 1a
if $anything; then
        echo 'true 1a'
fi
# result is true. But I don't understand why since bash will translate $anything to an empty string, shouldn't this will result in syntax error ?

# behavior 2a
if ''; then
        echo 'true 2a'
fi
# syntax error cause 'list' is empty and command can not be found

# behavior 3a
if 0; then
        echo 'true 3a'
fi
# syntax error cause 'list' is 0 and there is no such command as 0

# behavior 4a
if ; then
        echo 'true 4a'
fi
# syntax error cause list is empty


set +x
  • 1
    Deeply related, possible duplicate: null string as command in while loop: empty/null-command – Michael Homer Jun 29 '17 at 8:48
  • I see, thanks for pointing that out. But then this brings another question: why behavior 1 is false if to decide whether true or false,it is to evaluate the return code and not what translated by bash(means empty string). If using such logic, behavior 1a is true, then behavior 1 should be true also ? I think this question is worth answer as it brings up the 'test' condition and compare together with the list scenario side by side and trigger more brainstorming. – sylye Jun 29 '17 at 9:20
  • Arguments to test are different than commands. – Michael Homer Jun 29 '17 at 9:21
  • Maybe you could elaborate more about the different with an answer then we can all learn from that :) thanks and appreciated the efforts! (And also do help to verify whether my explanation on other behaviors give any wrong concept or not) – sylye Jun 29 '17 at 9:26
3

result is true. But I don't understand why since bash will translate $anything to an empty string, shouldn't this will result in syntax error ?

Close, but no biscuit. There is an expression: $anything. if ; then is an error because bash fails to parse it (hence: syntax error). It expects a command list there and gets a ; instead. Parsing happens well before variable expansion happens, so if $anything; then parses fine. What happens next? $anything is expanded, and field splitting, etc. done. This leaves an empty command list, which is trivially true. Compare:

if "$anything"; then echo foo; fi
if $anything; then echo foo; fi

"$anything"; isn't an empty command list, it has command which happens to an empty string, the same as with if '';. But an unquoted "$anything" expands to nothing.

The same would be true if $anything contained only whitespace characters present in IFS, or contained a $IFS-separated list of globs that didn't match any file and the nullglob option was on.

  • Not very understand with this: "$anything"; isn't an empty command list, it has command which happens to an empty string. Is "$anything" interpreted by bash as a command or variable expansion ? And would be appreciated if you can verify my other if statement behavior is giving correct reason on the result or not, and maybe doing comparison with the one with and without the test and why they are different. – sylye Jun 30 '17 at 6:19
0

The brackets in statements like [ "$foo" ] are a sort of shorthand for the test command, i.e. [ "$foo" ] and test "$foo" are equivalent.

On the other hand, just entering a blank, or an unset string, returns a true exit code:

unset foo; $foo; echo $?
0

Compare to:

unset foo ; test $foo ; echo $?
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.