What is a best practice to represent a boolean value in a shell script?

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?

  • 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 
                return 1 

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.

Asked By: Minix

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}"

…which would print…

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.

Answered By: mikeserv

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

Answered By: orion

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

Answered By: YoMismo
Categories: Answers Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.