The elif condition

In the scenarios we've seen up until now, there was only ever the need to check for one if condition. But as you might expect, sometimes, there are multiple things that you want to check for, each with their own sets of following actions (then block). You could solve this by using two full if-then-else statements, but at the very least you'd have a duplicate else block. Even worse, if you have three or more conditions you want to check for, you'll have more and more duplicate code! Luckily for us, we can solve this by using the elif command, which is part of the if-then-else logic. As you've probably guessed, elif is short for else-if. It allows us to do something like the following:

IF condition1, THEN do thing1, ELIF condition2, THEN do thing2, ELSE do final-thing

You can chain as many elif commands after the initial if command as you want, but there is one important thing to consider: as soon as any condition is true, only that then statement is executed; all others are skipped.

If you're thinking of a situation in which multiple conditions can be true, and their then statements should be executed, you need to use multiple if-then-else blocks. Let's look at a simple example that first checks if the argument given by the user is a file. If it is, we print the file using cat. If this is not the case, we check if it is a directory. Should this be the case, we list the directory with ls. If this is also not the case, we'll print an error message and exit with a non-zero exit status. Look at the following command:

reader@ubuntu:~/scripts/chapter_11$ vim print-or-list.sh 
reader@ubuntu:~/scripts/chapter_11$ cat print-or-list.sh
#!/bin/bash

#####################################
# Author: Sebastiaan Tammer
# Version: v1.0.0
# Date: 2018-10-26
# Description: Prints or lists the given path, depending on type.
# Usage: ./print-or-list.sh <file or directory path>
#####################################

# Since we're dealing with paths, set current working directory.
cd $(dirname $0)

# Input validation.
if [[ $# -ne 1 ]]; then
echo "Incorrect usage!"
echo "Usage: $0 <file or directory path>"
exit 1
fi

input_path=$1

if [[ -f ${input_path} ]]; then
echo "File found, showing content:"
cat ${input_path} || { echo "Cannot print file, exiting script!"; exit 1; }
elif [[ -d ${input_path} ]]; then
echo "Directory found, listing:"
ls -l ${input_path} || { echo "Cannot list directory, exiting script!"; exit 1; }
else
echo "Path is neither a file nor a directory, exiting script."
exit 1
fi

As you can see, when we're dealing with file input by users, we need extra sanitation. We make sure to set the current working directory in the script with cd $(dirname $0), and we assume that every command can fail, so we handle these failures with the || construct, as explained in Chapter 9, Error Checking and Handling. Let's try and see if we can find most of the paths that this logic can take:

reader@ubuntu:~/scripts/chapter_11$ bash print-or-list.sh 
Incorrect usage!
Usage: print-or-list.sh <file or directory path>
reader@ubuntu:~/scripts/chapter_11$ bash print-or-list.sh /etc/passwd
File found, showing content:
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
<SNIPPED>
reader@ubuntu:~/scripts/chapter_11$ bash print-or-list.sh /etc/shadow
File found, showing content:
cat: /etc/shadow: Permission denied
Cannot print file, exiting script!
reader@ubuntu:~/scripts/chapter_11$ bash print-or-list.sh /tmp/
Directory found, listing:
total 8
drwx------ 3 root root 4096 Oct 26 08:26 systemd-private-4f8c34d02849461cb20d3bfdaa984c85...
drwx------ 3 root root 4096 Oct 26 08:26 systemd-private-4f8c34d02849461cb20d3bfdaa984c85...
reader@ubuntu:~/scripts/chapter_11$ bash print-or-list.sh /root/
Directory found, listing:
ls: cannot open directory '/root/': Permission denied
Cannot list directory, exiting script!
reader@ubuntu:~/scripts/chapter_11$ bash print-or-list.sh /dev/zero
Path is neither a file nor a directory, exiting script.

In order, we've seen the following scenarios for our script:

  1. No argument: Incorrect usage error
  2. File argument /etc/passwd: File content printed
  3. File argument on non-readable file /etc/shadow: Cannot print file error
  4. Directory argument /tmp/: List of directory printed
  5. Directory argument on non-listable directory /root/: Cannot list directory error
  6. Special file (block device) argument /dev/zero: Path is neither a file nor a directory error

These six input scenarios represent all of the possible paths our script can take. While you might have considered all of the error handling for a (seemingly simple) script a bit over the top, these arguments should validate why we actually need all of this error handling.

While elif greatly enhances the possibilities of an if-then-else statement, too much if-elif-elif-elif-.......-then-else will make your script really hard to read. There is another construct (which is outside the scope of this book), called case. This deals with many different, unique conditions. Look at the further reading section at the end of this chapter for a good resource on case!
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.145.109