Twitter

Some bash tips -- 8 -- check many variabes at once with indirect expansion

This blog is part of a bash tips list I find useful to use on every script -- the whole list can be found here.

Number of lines in a script do not really matter; whether you use 100 lines to show numbers from 1 to 100 or use some magic bracket tricks (we'll see that later) to do the same, this won't change much except how neat is your code, how proud you are of your code, how easy you will maintain your code and how easy and fast you could debug it.

One thing we use to do a lot in many scripts is verifying variables given to the script by the users. We often check if some files exist or if some variables are given (not empty). A single IF is perfect for this if you have one variable to verify but what if you have a lot of them ?

Let's use these 3 variables for the purpose of this example:
P1="abc"
P2=""
P3="zzz"
We can obviously test them as below with some oneliners IF:
if [[ -z "${P1}" ]]; then echo "P1 is empty; cannot continue !"; exit 123; fi
if [[ -z "${P2}" ]]; then echo "P2 is empty; cannot continue !"; exit 123; fi
if [[ -z "${P3}" ]]; then echo "P3 is empty; cannot continue !"; exit 123; fi
But what if you have 10 or more of them to check ? also, we can see here that a lot of code is duplicated and it would obviously be better to have only one line doing one thing many times instead of many lines doing the same thing.
A for loop like the below one would be the way to go:
$ for P in P1 P2 P3; do
    echo "${P}"
done
P1
P2
P3
$
But this shows the name of the variables, not the values of these variables; this is because we use the names of the variables we want to test in the for loop list then "${P}" contains the name of these variables, makes sense, it is how it works. To achieve what we want to do and have the values of these variables, we have to use what is called indirect expansion which is achieved by using an exclamation mark before the variable name, as shown below (in orange):
$ for P in P1 P2 P3; do echo "${P} value is ${!P}"; done
P1 value is abc
P2 value is
P3 value is zzz
$
Very cool, right ? so our single loop testing if all of these variables are empty before being able to continue further would look like (I will also use a oneliner with && now that we know how to use $$ and ||):
$ for P in P1 P2 P3; do [[ -z "${!P}" ]] && { echo "${P} is empty, cannot continue"; exit 123; }; done
P2 is empty, cannot continue
$
And if you were to verify if some files exist; it would look like (with no oneliner):
for F in F1 F2 F3 F4; do
    if [[ ! -f "${!F}" ]]; then
        echo "File does not exist, cannot continue";
        exit 123;
    fi
done
And the same in one line:
for F in F1 F2 F3 F4; do [[ ! -f "${!F}" ]] && { echo "File does not exist, cannot continue"; exit 123; }; done

All in one line to check any number of variables or files, clear and neat code, easy to maintain, easy to debug -- the way to go !


< Previous bash tip / Next bash tip >

No comments:

Post a Comment

Some bash tips -- 18 -- paste

This blog is part of a shell tips list which are good to know -- the whole list can be found here. I really like finding a real usage for...