Why are both “true” and “false” tests true?

不想你离开。 提交于 2020-01-22 16:21:07

问题


The words "true" and "false" are special words (builtins) for bash. If used in an if test, 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, this two tests:

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

Both result in true. Why?


回答1:


[[ … ]] is, in this case, equivalent to test, i.e. test true and test false. Looking at the manual for test(1):

-n STRING the length of STRING is nonzero

STRING equivalent to -n STRING

true and false are both non-empty strings.




回答2:


This is because in your first example, true is a builtin command.

In your second exmaple, however, the true inside [[ true ]] is not interpreted as a command, but just treated as a string-like token, and it returns true if string is not empty.

The second example could be written like this for fix:

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



回答3:


When we use test or its equivalent [ we, sometimes, get strange results. Lets try to understand why that happens.

We can make simple tests manually:

$ 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 intermediately shocked that both the above tests are reported as true. Is test telling us that 0 is equal to 1 ?

To answer this question we could create a testing function and run all the tests that appear in this page.
A page which also aims to explain all the details with "test". With the aid of the testing function, we could run an script similar to the next one. It prints both the result of the test and the exit value of the function 'test':

#!/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"

The 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 tests above, it becomes clear the rule for unary test:

    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's lenght is not zero, it's result is TRUE.

Well, that is the whole true for any "unary" test. i.e. Tests perform on values that could NOT be split with spaces. Tests that are binary [ -n $var ] or ternary [ 1 -eq "$one" ] result in a true value if the conditions (-n or -eq) are valid.
Amazingly, this (more complex) binary or ternary tests are more intuitive to understand. There exist a huge list of longer tests, but I feel that those fall outside the scope of this short question.

It is sometimes called pedantic to ask if a var is NOT zero length with the condition -n as exactly the same test happens without any explicit condition.

However, it is often clearer to the reader what is the goal of the programer when the condition -n is explicitly used.
The condition -z tests for "zero length".

With this 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 test? Thanks.



来源:https://stackoverflow.com/questions/30229547/why-are-both-true-and-false-tests-true

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!