0

I am trying to figure out why bash "miss-behaves":

REG=true 
VIN=false

if $REG -a $VIN; then
    echo $REG $VIN
fi

when run, it yields:

$ bash test.sh 
true false

I was expecting nothing, can you show how to make a complete evaluation of both variables ?

oz123
  • 27,559
  • 27
  • 125
  • 187

3 Answers3

2

In REG=true, 'true' is a string. When you do $REG, you're executing the command true.

if $REG -a $VIN means "run the command true with the option '-a' and argument '$VIN', which are ignored by true. So it's the same as if you had if true.

if $REG && $VIN causes 'true' and 'false' to be executed and their results 'and-ed', which yields false.

if [ "$REG" -a "$VIN" ] DOES NOT WORK (as defined here). This is the same as if test "true" -a "false". Any non-null string is true, so this statement is true. Same goes for if [[ "$REG" && "$VIN" ]]

However:

if [[ `$REG` && `$VIN` ]] # works

does work because here you execute the commands true and false.

zanerock
  • 3,042
  • 3
  • 26
  • 35
1

Use && instead in the most POSIX way:

if [[ "$REG" && "$VIN" ]]; then
    echo $REG $VIN
fi

If you want to use the -a, then surround with brackets:

if [ "$REG" -a "$VIN" ]; then

if $REG && $VIN; then
fedorqui
  • 275,237
  • 103
  • 548
  • 598
  • 1
    thanks, I never saw that you can use `&&` without `[[` or `[` – oz123 Jan 14 '14 at 14:37
  • It is always tricky. I recommend the read of pages like http://wiki.bash-hackers.org/syntax/ccmd/conditional_expression – fedorqui Jan 14 '14 at 14:57
  • Neither `[[ "$REG" && "$VIN" ]]` nor `[ "$REG" -a "$VIN" ]`, because they both check the strings "$REG" and "$VIN" to see if they're nonblank -- that is, they consider "true" and "false" to both be true (nonblank). – Gordon Davisson Jan 14 '14 at 16:57
  • Oh, I see @GordonDavisson. And does `if $REG && $VIN;` work then? – fedorqui Jan 14 '14 at 16:59
  • @fedorqui: Yes, `if $REG && $VIN;` works because it treats the two strings as commands; `true` is actually a command that always succeeds, `false` is a command that always fails, and the `&&` makes a compound command that succeeds only if both individual commands succeed. This is what you want. – Gordon Davisson Jan 14 '14 at 17:02
  • Good point, thanks for the patience @GordonDavisson . I just updated my answer to be correct. – fedorqui Jan 14 '14 at 17:04
1

Correct way for you would be:

if [[ $REG = 'true' && $VIN = 'true' ]]; then
    echo "$REG $VIN"
fi

This is the most correct and safe way (unlike executing your $REG and $VIN as other answers suggest). For example, what is going to happen if $REG variable is empty? Or what if it equals to something different than just true or false?

If you want boolean behavior in bash, then consider the fact that empty strings are falsy.

REG=1
if [[ $REG ]]; then
    echo '$REG is true!'
fi

or like that for multiple variables:

REG=1
VIN=''

if [[ $REG && $VIN ]]; then
    echo '$REG and $VIN are true!'
fi
if [[ $REG && ! $VIN ]]; then
    echo '$REG is true and $VIN is false!'
fi

So, if you want something to be false, then either leave it unset or use an empty string.

Aleks-Daniel Jakimenko-A.
  • 10,335
  • 3
  • 41
  • 39