21

I know, that there are boolean values in bash, but I don't ever see them used anywhere.

I want to write a wrapper for some often looked up information on my machine, for example, is this particular USB drive inserted/mounted.

What would be the best practice to achieve that?

  • A string?

    drive_xyz_available=true
    
  • A number (0 for true, ≠0 for false)?

    drive_xyz_available=0    # evaluates to true
    
  • A function?

    drive_xyz_available() { 
        if available_magic; then 
                return 0 
        else 
                return 1 
        fi
    }
    

I mostly wonder about, what would be expected by other people who would want to use the wrapper. Would they expect a boolean value, a command like variable or a function to call?

From a security standpoint I would think the second option is the safest, but I would love to hear your experiences.

2
  • 5
    help true ; help false ; help exit
    – Costas
    Commented Feb 19, 2015 at 10:00
  • 5
    @Costas Would you mind elaborating?
    – Minix
    Commented Feb 19, 2015 at 10:29

3 Answers 3

6
bool(){ return "$((!${#1}))"; }

if bool "$var"
then : do true
else : do false

Just set a variable to anything but not-null for the above to work, though [ -n "$var" ] would be shorter, if not as obvious.

In general when a script interprets an environment variable to be either true or false, it will interpret any value at all to be true (and sometimes use said value to configure some option) or else a null value as false.

The above returns the boolean !not value of its first argument's len - if the argument contains any number of characters other than 0 it returns 0, else, if no characters at all, it returns 1. This is the same test you can perform with [ -n "$var" ], basically, but it just wraps it in a little function named bool().

This is typically how a flag variable works. For example:

[ -d "$dir" ] || dir=

Where other parts of a script need only look for any value at all in $dir to gauge its usefulness. This also comes in handy where parameter substitution is concerned - as parameters can be expanded to default values to fill in for empty or unset ones, but will otherwise expand to a preset value like...

for set in yes ''
do echo "${set:-unset or null}"
done

...which would print...

yes
unset or null

Of course, it is also possible to do the opposite with :+ but that can only ever give you a preset default or nothing at all, whereas the above form can give you a value or a default value.

And so regarding the three choices - any one could work depending on how you choose to implement it. The function's return is self-testing, but, if that return needs saving for any reason, will need to be put in a variable. It depends on the use case - is the boolean value you wish to evaluate a test once and done type? If so, do the function, else either of the other two is probably necessary.

8
  • 1
    I don't think you're answering my question. I'm not asking how booleans could be used in a shell script, but what way is the most common and would be expected by another user. If my question is unclear I would be happy to edit it. Also a short explanation for what your answer does would be nice. Thank you.
    – Minix
    Commented Feb 19, 2015 at 10:50
  • @Minix Any better?
    – mikeserv
    Commented Feb 19, 2015 at 11:07
  • 2
    @wurtel - that relies on default $IFS - and if the var's value might contain user input of any kind, then also on sheer good luck. If the value is not unknown to begin with then there is little need to test it. More safely you can do if ${var:+":"} false; then when working w/ boolean null/not null values. But that is rarely more useful than [ -n "$var" ] &&
    – mikeserv
    Commented Feb 19, 2015 at 11:39
  • 2
    @wurtel - no obsession, it's just important to handle all cases. Unintended behavior is a bug - good code is bug free. $IFS is a global modifier - it affects all of the code you write, and, for POSIX shells, can be passed in via the environment. So IFS=t wurtel.sh would cause your test to fail in that case. Given a POSIX sh, that is, and an #!/bin/sh bangline. bash, for example, though, ignores $IFS in the environment. But a bash bangline only limits the usefulness of your code more than it need be because you didn't like the quotes.
    – mikeserv
    Commented Feb 19, 2015 at 11:50
  • 2
    @wurtel - which is a good idea. But a user going out of their way to do bizarre things with the environment in which the code you write is executed should be your expectation in the first place - robust code handles it, buggy code doesn't.
    – mikeserv
    Commented Feb 19, 2015 at 12:11
5

In bash every variable is essentially a string (or an array or a function, but let's talk about regular variables here).

The conditions are parsed based on the return values of the test commands -- the return value is not a variable, it's an exit state. When you evaluate if [ ... ] or if [[ ]] or if grep something or anything like that, the return value 0 (not string 0, but exit status 0 = success) means true and the rest mean false (so, exactly the opposite from what you are used to in compiled programming languages, but because there is one way to succeed and many ways to fail, and the expected outcome of execution is usually success, 0 is used as the most common default result if nothing goes wrong). This is very useful because any binary can be used as a test - if it fails, it's false, otherwise it's true.

true and false programs (usually overridden by builtins) are just usefull little programs that do nothing -- true succeeds at doing nothing, and exits with 0, while false tries doing nothing and "fails", exitting with 1. Sounds pointless but it's very handy for scripting.

As for how to pass truthfullness around, it's up to you. It's quite common to just use "y" or "yes" for truth and use if [ x"$variable" = x"yes" ] (appended the dummy string x because if $variable happens to be zero length, this protects from creating a bogus command if [ = "yes" ] which doesn't parse). It may also be useful to simply use an empty string for false, and use [ -z "$variable ] to test if it's zero-length (or -n for it to be nonzero).

Anyway, it's quite rare to actually need to pass around boolean values in bash - it's much more common to simply exit on failure, or return a useful result (or zero if something goes wrong, and test for empty string), and most of the cases can test for failure directly from the exit statatus.


In your case, you want a function that will act as any other command (therefore, return 0 on success), so your last option seems the right choice.

Also, you may not even need return statement. If the function is simple enough, you can use the fact that it simply returns the status of the last executed command in the function. So your function can simply be

drive_xyz_available() {
   [ -e /dev/disk/by-uuid/whatever ]
}

if you are testing for existence of a device node (or grep /proc/mounts to check if it's mounted?).

4
  • That's a very nice summary, thank you for taking the time to write it up. Can I infer from your last paragraph, that you would consider the option of drive_xyz_available() to be the most common?
    – Minix
    Commented Feb 19, 2015 at 10:47
  • Can you provide some examples for the common y = true case? In my experience, most wrapper scripts test for any not null value to consider it true - at least where interpreted environment variables are concerned. Otherwise they ignore shell cars altogether.
    – mikeserv
    Commented Feb 19, 2015 at 10:54
  • 4
    The dummy string for the if test is not necessary if the variable is quoted; if [ "$variable" = "yes" ] works fine even if $variable is not set. Commented Feb 19, 2015 at 10:59
  • true and false programs (usually overridden by builtins) are just usefull little programs that do nothing -- true succeeds at doing nothing, and exits with 0, while false tries doing nothing and "fails", exitting with 1. Sounds pointless but it's very handy for scripting. When using return, isn’t return 0 a tiny bit more effective than return true? Because the second one implies calling a program, whereas 0 is more “direct”? Probably a silly question… and sure return true is far more easy to read.
    – Stéphane
    Commented Jan 19 at 17:24
-2

Basically any number that is not 0 is true, and 0 is false. Reason for returning values as 0 for a successfull ending of a script or any other number to identify different kind of errors.

$? will return the exit code of the previous command/executable, being 0 success and any other number the error that has been returned.

So I would use that method for true/false. if (( ! $? ));then OK;else NOOK;fi

6
  • I'll write one up for the last option, then. Thank you.
    – Minix
    Commented Feb 19, 2015 at 10:58
  • 6
    A nonzero number is false actually, and zero is true. Just look at output of true; echo $? and false; echo $?.
    – Ruslan
    Commented Feb 20, 2015 at 13:31
  • @Ruslan. Did you check the output of my command? I guess you didn't, otherwise you wouldn't have stated what you did. 0 is false, any other number is true, reason to negate ! the result for it to be TRUE. Result from a command is 0 when it has finished correctly, which doesn't mean that 0 is true. The word true may be 0, but 0 is never true as the if condition demonstrates.
    – YoMismo
    Commented Feb 23, 2015 at 7:45
  • That's the same as saying that in C/C++, 0 is true because if(!x){True();}else{False();} will call True() when x==0. But the correct check would be not !x, but rather !!x.
    – Ruslan
    Commented Feb 23, 2015 at 9:23
  • 1
    You are waaaaaaay wrong. I'm not talking about what and which order has whatever you write after the if I just state the fact that here (in bash, or ksh, or tsh, or....) as in C/C++ a 0 is FALSE, any other number is TRUE, as you can read in the link that follows, initial implementatins of C provided no boolean type, being defined as ints where 0 was FALSE and 1 TRUE en.wikipedia.org/wiki/Boolean_data_type.
    – YoMismo
    Commented Feb 23, 2015 at 9:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .