Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Well, the variable is not boolean until it has been set to true or false.

So when the script begins, it checks for a boolean that was not set yet as in bTest=''. So if I do this: if $bTest;then echo "is active";fi it will output "is active" when I would like it to show nothing...

I could use this: [ "$bTest" == true ], when before was just $bTest, but to me that is the problem, it is not a "boolean", it is a string comparison...

Also, if I misstype a boolean variable name, it will be empty, and the script execution will throw no error message... and for several times I discovered the real problem was just the misstyped variable... Could an IDE have get that? I use gedit so I must track my failures by myself.

I wonder if is there a clean and simple way to work with booleans instead of typing [ "$bTest" == true ] every time..?

share|improve this question
1  
I believe true here is the literal string "true", not a boolean value of true. So you can consider "" as false and any other value as true. To check, you can use the -z "$var" test operator (to check for a zero-length string). –  aularon Feb 2 at 20:21
    
try this on terminal true;echo $?;false;echo $?, I think it is not just a string :). Also, my code would become this [ ! -z "$bTest" ] && $bTest and I would still be considering it as a string :( –  Aquarius Power Feb 2 at 20:27
1  
true and false are shell builtins. true returns a status of 0, while false returns a status of 1. When doing [ "$bTest" == true ] you are not executing true, but rather comparing the string true to the string content of $bTest. –  aularon Feb 2 at 20:30
add comment

4 Answers 4

up vote 2 down vote accepted

Based on your answer, it sounds like you're actually trying to avoid typos.

The best way to do this, is to put

set -u

at the top of your shell script.

Then, instead of a typo expanding to an empty string, it is a fatal error.

if $bTest; then
    echo "is active"
fi

# => is active

Versus

set -u
if $bTest; then
    echo "is active"
fi

# => typo.sh: line 4: bTest: unbound variable

Alternatively, if you want to assign defaults to variables, it's usually best to do all the assignments at the top of the script like this:

: ${bTest:=false}

Finally, if you really want to type out a default value every time, you could use

if ${bTest:-false}; then
    echo "is active"
fi
share|improve this answer
    
cool, this works great for unset variables! as I make it sure to initialize them all, this may work indeed thx! –  Aquarius Power Feb 2 at 22:19
    
I am having trouble with empty parameters like $1 or ${1:0:1}, any tips? –  Aquarius Power Feb 2 at 22:44
1  
How about ${1:-false}? –  samiam Feb 2 at 22:47
    
it is my options loop: while [[ "${1:0:2}" == "--" ]];do I am trying to find a workaround.. –  Aquarius Power Feb 2 at 22:53
    
For $1, it's more common to handle that explicitly at the start, e.g. if test $# -eq 0; then echo "Usage..."; exit 2; fi. Or use getopts. –  Mikel Feb 3 at 0:07
show 3 more comments

The simplest way is this:

if ${bTest:?};then echo "is active";fi

So I simply go from $bTest to ${bTest:?} and no need to deal with anything more complex like functions and aliases.

Be concerned that as @samiam pointed out, it may cause a problem to you if the variable was actually set to something and that was a command like in bTest='ls -l';if ${bTest:?};then echo "is active";fi (where ls -l will be executed).

But in my case, I treat all "booleans" as booleans, so I only put true or false on them; the biggest problem I have been having with them for years is misstyped variable names; so I always got an empty "boolean" troubling me until I found that I misstyped it..

So, if you use your "booleans" with other values than true or false, do not use it; as it may become unsafe.

share|improve this answer
1  
-1: Inaccurate (I just tested it in Bash). That code expands the value of bTest in to a command run by Bash, and generates an error when bTest is not set. bTest='ls -l';if ${bTest:?};then echo "is active";fi will run ls -l. I'll undo my downvote as soon as the answer is corrected. –  samiam Feb 2 at 20:53
1  
thx, I understand your concern about safety, but in my case I only use true or false with booleans. And before ${bTest:?} I was already using $bTest and would already execute anything there! I still believe there may have some safer and still clean way to deal with it, I just couldnt figure out yet.. –  Aquarius Power Feb 2 at 21:18
    
Is if [-z "$bTest" ]; then echo "is active"; fi clean enough for you? If you really want it to look more boolean-like, there is FALSE="";if[ "bTest" != "$FALSE" ] etc. –  samiam Feb 2 at 21:25
    
if I set bTest=true it wont work with solely [ -z "$bTest" ]. I want to test the boolean in a way that if it is empty, it be evaluated as false or throw error message. ${bTest:?} worked perfectly, but has the flaw you said, but not in my case as I only use true or false for booleans! –  Aquarius Power Feb 2 at 21:31
    
I have updated my answer to use functions called is_true and is_false. I don't like throwing errors in Bash scripts because it halts execution when a script is called with #!/bin/bash -e (-e: Halt on any error) –  samiam Feb 2 at 21:33
add comment

Bash does not have a boolean datatype (/bin/true and /bin/false are commands which return 1 and 0, because Bash, unintuitively interprets a return code of 0 as 'all is good' and anything else as 'there was a problem')

Indeed, Bash does not have a numeric datatype (A=$(( $A + 1 )) converts $A in to an integer, adds one to it, then makes it a string again) and, more to the point, 0 does not have the same value as the empty string. BASH is not PHP (where var_dump(0 == ""); returns true).

Probably the best way to simulate booleans is as per aularon's suggestion: Use the -z operator, and consider empty strings false. e.g [ ! -z "$bTest" ] && $bTest

If that's not clean enough for you, how about having is_true and is_false functions?

#!/bin/bash

is_true() {
        if [ "$1" = "false" ]; then
                return 1 # false
        fi
        if [ -z "$1" ]; then
                return 1 # false
        else
                return 0 # true
        fi
}

is_false() {
        if [ "$1" = "false" ]; then
                return 0 # true
        fi
        if [ -z "$1" ]; then
                return 0 # true
        else
                return 1 # false
        fi
}

A="1"
B=""

if is_true "$A" ; then
        echo A is true
else
        echo A is false
fi

if is_false "$A" ; then
        echo A is false
else
        echo A is true
fi

if is_true "$B" ; then
        echo B is true
else
        echo B is false
fi
share|improve this answer
    
in other words, you mean everything in bash are strings right? I understand the arguments, but I am still concerned about the simplicity and clean coding, try this ${bTest:?} and the result will be what I was looking for! –  Aquarius Power Feb 2 at 20:58
    
Exactly! Bash is a bit of a hack if you want super-clean code. It is not Python. As another example, one has to explicitly variables to be local in functions. –  samiam Feb 2 at 21:00
    
my booleans are intended solely to true or false, this failed: bTest=false;if is_true $bTest;then echo "is active";fi –  Aquarius Power Feb 2 at 21:44
    
Having the string "false" evaluate to false is not how I would do it, but I have added code to make the is_true() and is_false() functions work that way. –  samiam Feb 2 at 21:56
    
the is_true is still failing for this bTest=false;if is_true $bTest;then echo "is active";fi :( –  Aquarius Power Feb 2 at 22:08
show 3 more comments

Shells convert environment variables to shell variables. So you should never use a variable uninitialised as one day or another your script will break because for a reason or another a variable by the same name was in the environment that shell received on startup.

So:

#! /bin/sh -
bTest=false

while getopts ...;
  ... ) bTest=true
done

if "$bTest"; then

(don't forget the quotes, leaving out the quotes is the split+glob operator. Note that if $bTest is empty, you'll get an error about the empty string being not found as a command).

Now, if you want to ignore the advice. Another way using ksh syntax (works also in bash and zsh) is to use arithmetic expressions and 1 or any non-zero value to mean true.

0 and the empty string mean false in arithmetic expressions.

So you can do:

#! /bin/bash -
while getopts ...;
  ... ) bTest=1
done
if ((bTest)); then...

But beware that your script may stop working if for some reason there's a bTest in the environment (for instance because your script is called from another script that uses the same variable name and exported it (for instance because of a set -a or because it's a rc script where all variables are in the environment)).

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.