elif is a portmanteau consisting of the words "else" and "if". In bash (and Python), it's a way to test multiple statements before closing a loop, as opposed to the single statement test provided by else. If a typical if/then construct uses an if/then/else format, elif allows for if/then/elif/then/else.
Here is a simple example that will try to start mysql if mariadb is active on the system, psql if postgresql is active on the system. Below the example is a breakdown of what each line does:
[user@host ~]$ systemctl is-active mariadb > /dev/null 2>&1
MARIADB_ACTIVE=$?
[user@host ~]$ systemctl is-active postgresql > /dev/null 2>&1
POSTGRESQL_ACTIVE=$?
[user@host ~]$ if [ "$MARIADB_ACTIVE" -eq 0 ]; then
> mysql
> elif [ "$POSTGRESQL_ACTIVE" -eq 0 ]; then
> psql
> else
> echo "Nuts, all outta databases here!"
> fi- This line asks
systemctlto check if themariadbserviceis-active, and to send any output (error or otherwise) to/dev/null, or nowhere.
Fun Fact:2>&1Refers to something very basic about how Unix systems operate: standard input (stdin), standard output (stdout) and standard error (stderr).
stdin (0) is a keyboard - what you use to input information
stdout (1) is the terminal - where output is displayed
stderr (2) are errors.
So2>&1is saying to send any errors (2) from this command to the same location as standard output (1), which in this case is /dev/null, the black hole of all Linux filesystems. - Set a variable called
MARIADB_ACTIVE, the value of which is the result of$?, which returns exit codes from the immediately previous command. Ifmariadbwas active, the exit code would be0. If it's not running, or not installed, it would be another number, between 1 and 255. In this instance,mariadbis not installed, so the exit code is3.
Unfamiliar with exit codes? In bash, you can check the exit code of the previous command by typingecho $?, which will output EITHER a 0 or any other number. If the previous command was successful, you always get a 0. Any other number is a fail. - Ask
systemctlto check if thepostgresqlserviceis-activeand send any output (and errors) to/dev/null. - Set a variable called
POSTGRESQL_ACTIVEwith the value of the exit code$?for the command from the previous line. In this instance,postgresqlis also not installed, so the exit code is3. - If/then loop using a
testexpression. This is saying thatifthe value of the variableMARIADB_ACTIVEis equal (-eq) to0,then - Run
mysqlif the previous line can be processed. In this instance, the value ofMARIADB_ACTIVEis3, so the test failed, and we go to the next line: elif(else if) the previous command failed, try anothertestexpression - in this case,ifthe value ofPOSTGRESQL_ACTIVEis equal (-eq) to0, then- Run
psqlif thetestexpression succeeded - it didn't, because the value ofPOSTGRESQL_ACTIVEis3, so we go to the next line: else- ifeliffailed and can't runpsqlon the previous line, go to the next line- Neither mariadb nor postgresql is installed, so we're just going to output text that says
"Nuts, all outta databases around here!". fi- The inverse of if and closes out the if/then loop.
Just for super geeky funsies, let's write a bash script to cover Bilbo's thought processes about taking the ring back at Rivendell, using elif:
systemctl is-active mordor-desire > /dev/null 2>&1
MORDOR_DESIRE=$?
systemctl is-active wanna-turn-into-a-gollum /dev/null 2>&1
GOLLUM_DESIRE=$?
if [ "$MORDOR_DESIRE" -eq 0 ]; then
> echo "I'm going on an adventure!"
> elif [ "$GOLLUM_DESIRE" -eq 0 ]; then
> echo "REEEEEEEEEEEEEE"
> else
> echo "I'm sorry that you must carry this burden"
> fi