Why are true and false tests correct?

The words "true" and "false" are special words (built-in) for bash. When used in a test if

, they act as intuitively expected:

$ if true; then echo "true"; else echo "false"; fi
true
$ if false; then echo "true"; else echo "false"; fi
false

      

However, these two tests:

$ [[ true ]] && echo "true" || echo "false"
true
$ [[ false ]] && echo "true" || echo "false"
true

      

Both results are true. Why?

+3


source to share


3 answers


[[ … ]]

in this case it is equivalent test

, i.e. test true

and test false

. Looking at the manual for the test (1):

-n STRING

STRING length is not zero

STRING

equivalent to -n STRING



true

and false

are non-empty strings.

+9


source


This is because in your first example there true

is a builtin command.

However, the second example does not true

internally [[ true ]]

interpret it as a command, but simply treats it as a string token and returns true if the string is not empty.



The second example can be written like this: to fix:

$ true && echo "true" || echo "false"
true
$ false && echo "true" || echo "false"
false

      

+2


source


When we use a test or its equivalent [

, we sometimes get strange results. Let's try to understand why this is happening.

We can do simple tests by hand:

$ test 0    && echo "0 is T|$?" || echo "0 is F|$?"
0 is T|0
$ test 1    && echo "1 is T|$?" || echo "1 is F|$?"
1 is T|0

      

or

$ [ 0 ] && echo "0 is T|$?" || echo "0 is F|$?"
0 is T|0
$ [ 1 ] && echo "1 is T|$?" || echo "1 is F|$?"
0 is T|0

      

And be shocked that both of the above tests are reported as true. Does the test show that 0 is 1?

To answer this question, we could create a test function and run all tests that appear on this page .
A page that also aims to explain all the details with a "test". With the test function, we could run a script similar to the following. It prints both the test result and the output value of the "test" function:

#!/bin/bash --
tval(){
    printf "test %s\t" "$1"; shift
    [ "$@" ] && printf "%15s is T|%s" "$*" "$?" || printf "%15s is F|%s" "$*" "$?"
    printf "\n" 
}

tval "zero" "0"
tval "one"  "1"
tval "minus 1"  "-1"
tval "string"   "xyz"
tval "false"    "false"
tval "true"     "true"

tval "empty"    ""
tval "Null"     ""
tval "null var" "$xyz"
tval "\$false"  "$false"
tval "\$true"   "$true"

      

Results:

test zero                     0 is T|0
test one                      1 is T|0
test minus 1                 -1 is T|0
test string                 xyz is T|0
test false                false is T|0
test true                  true is T|0
test empty                      is F|1
test Null                       is F|1
test null var                   is F|1
test $false                     is F|1
test $true                      is F|1

      

From all the above tests, the rule for a unary test becomes clear:

    The test command has a very simple mind.
    It always works is a very simple way.
Any time the tested value has some content, that is, it lenght is not zero, it result is TRUE.

Well, this is all true for any "unary" test. that is, tests execute values ​​that cannot be separated by spaces. Tests that are binary [ -n $var ]

or ternary [ 1 -eq "$one" ]

result in a true value if the conditions ( -n

or -eq

) apply .
Surprisingly, these (more complex) binary or ternary tests are more intuitive. There is a huge list of longer tests out there, but I feel they are outside the scope of this short question.

It is sometimes called pedantic to ask if var is not null-length with a condition -n

, since the exact same test happens without any explicit condition.

However, it often becomes clearer to the reader what the programmer's goal is when the condition is explicitly used -n

.
The condition -z

checks for "zero length".

With these tests:

xyz="str";  tval "-n var"       "-n" "$xyz"
xyz="str";  tval "-z var"       "-z" "$xyz"
one=1;      tval "1 -eq \$one"  "1" "-eq" "$one"
one=2;      tval "1 -eq \$one"  "1" "-eq" "$one"

      

We get:

test -n var              -n str is T|0
test -z var              -z str is F|1
test 1 -eq $one         1 -eq 1 is T|0
test 1 -eq $one         1 -eq 2 is F|1

      

Any missing aspect of the test? Thank.

0


source







All Articles