Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash Boolean testing

Tags:

bash

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!

like image 626
JLMarks Avatar asked Apr 27 '14 06:04

JLMarks


4 Answers

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.

like image 163
Ignacio Vazquez-Abrams Avatar answered Nov 04 '22 15:11

Ignacio Vazquez-Abrams


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
like image 32
devnull Avatar answered Nov 04 '22 15:11

devnull


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.)

like image 21
chepner Avatar answered Nov 04 '22 14:11

chepner


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.

like image 39
Idriss Neumann Avatar answered Nov 04 '22 14:11

Idriss Neumann