16

I am attempting to run a block of code if one flag is set to true and the other is set to false. ie

var1=true
var2=false
if [[ $var1 && ! $var2 ]]; then var2="something"; fi

Since that did not evaluate the way that I expected I wrote several other test cases and I am having a hard time understanding how they are being evaluated.

aa=true 
bb=false
cc="python"
if [[ "$aa" ]]; then echo "Test0" ; fi
if [[ "$bb" ]]; then echo "Test0.1" ; fi
if [[ !"$aa" ]]; then echo "Test0.2" ; fi
if [[ ! "$aa" ]]; then echo "Test0.3" ; fi
if [[ "$aa" && ! "$bb" ]]; then echo "Test1" ; fi
if [[ "$aa" && ! "$aa" ]]; then echo "Test2" ; fi
if [[ "$aa" ]] && ! [[ "$bb" ]]; then echo "test3" ; fi
if [[ "$aa" ]] && ! [[ "$cc" ]]; then echo "test4" ; fi
if [[ $aa && ! $bb ]]; then echo "Test5" ; fi
if [[ $aa && ! $aa ]]; then echo "Test6" ; fi
if [[ $aa ]] && ! [[ $bb ]]; then echo "test7" ; fi
if [[ $aa ]] && ! [[ $cc ]]; then echo "test8" ; fi

When I run the preceding codeblock the only output I get is

Test0
Test0.1
Test0.2

however, my expectation is that I would get

Test0
Test1
Test3
Test5
Test7

I have tried to understand the best way to run similar tests, however most examples I have found are set up in the format of
if [[ "$aa" == true ]];
which is not quite what I want to do. So my question is what is the best way to make comparisons like this, and why do several of the test cases that I would expect to pass simply not?

Thank you!

5 Answers 5

18

Without any operators, [[ only checks if the variable is empty. If it is, then it is considered false, otherwise it is considered true. The contents of the variables do not matter.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you. After I commented out the line bb=false and then reran the script I see how that works, it gave me output more in line with what I was expecting.
As an odd aside, this is the second question I have ever asked on stackoverflow, the first being over two years ago. In that question you where the only user to answer me. I just now got around to accepting your answer, so double thanks!
can you put a copy-pasteable answer here? the corrected code? thanks
18

Your understanding of booleans in shell context is incorrect.

var1=true
var2=false

Both the above variables are true since those are non-empty strings.

You could instead make use of arithmetic context:

$ a=1
$ b=0
$ ((a==1 && b==0)) && echo y
y
$ ((a==0 && b==0)) && echo y
$
$ ((a && !(b))) && echo y;       # This seems to be analogous to what you were attempting
y

1 Comment

You may combine this with readonly true=1 yes=1 no=0 false=0 to create reliable constants for true and false within arithmetic expressions.
13

The shell does not have Boolean variables, per se. However, there are commands named true and false whose exit statuses are 0 and 1, respectively, and so can be used similarly to Boolean values.

var1=true
var2=false
if $var1 && ! $var2; then var2="something"; fi

The difference is that instead of testing if var1 is set to a true value, you expand it to the name of a command, which runs and succeeds. Likewise, var2 is expanded to a command name which runs and fails, but because it is prefixed with ! the exit status is inverted to indicate success.

(Note that unlike most programming languages, an exit status of 0 indicates success because while most commands have 1 way to succeed, there are many different ways they could fail, so different non-zero values can be assigned different meanings.)

Comments

8

true and false are evaluated as strings ;)

[[ $var ]] is an equivalent of [[ -n $var ]] that check if $var is empty or not.

Then, no need to quote your variables inside [[. See this reminder.

Finally, here is an explication of the difference between && inside brackets and outside.

Comments

0

The closest you can come seems to be use functions instead of variables because you can use their return status in conditionals.

$  var1() { return 0; }
$  var2() { return 1; }  # !0 = failure ~ false

and we can test this way

$  var1 && echo "it's true" || echo "it's false"
it's true
$  var2 && echo "it's true" || echo "it's false"
it's false

or this way

$  if var1; then echo "it's true"; else echo "it's false"; fi
it's true
$  if var2; then echo "it's true"; else echo "it's false"; fi
it's false

Hope this helps.

1 Comment

See @chepner above: stackoverflow.com/a/23324368/1246494 true/false functions are built in to act as boolean values.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.