DEV Community

LJ Seng
LJ Seng

Posted on • Originally published at Medium

The elegance of bash chaining operators

I am new to bash scripting.

In my quest to pick it up, I begin to heartily appreciate chaining operators. With the help of chaining operators, I may not need if conditional check in bash as often as other programming languages, i.e. Java or PHP.

Furthermore, to my surprise, lesser if does not degrade the expressiveness of the script. Instead, it is more elegant and concise once I understand the quirk of it.

Let's see what do I mean by looking at the following example.

I need to write a bash script that make sure at any instance of time there is only a maximum of 10 certain files in a directory.

My first version of the script goes like this:

#!/bin/bash
set -u

##### Variable declaration #####

MY_DIR=~/rotateLog
MAX_FILE_COUNT=10

##### Method definition #####

_delete_oldest_file() {
    ls -1tr $MY_DIR/temp.log.* | head -1 | xargs rm -f
}

##### Main #####

while true
do
    FILE_COUNT=`ls -1tr $MY_DIR/temp.log.* | wc -l`

    if [ $FILE_COUNT -gt $MAX_FILE_COUNT ]; then
        _delete_oldest_file
    fi
done

Program flow is pretty straight forward, described below:

  1. Check current file count in the directory
  2. Remove the oldest file from directory if there is more than what is needed

if conditional check is always the de facto approach to tackle any sort of decision making problem. This script is okay.

Then, as I learn about chaining operators, i.e. &&, ||, ;, etc, which are used to chain commands together, I think the script could be rewritten in a more concise manner. Let's focus on && for the moment being.

&& is used to chain commands together, such that the next commands is run if and only if the preceding command exited without error (exit code of 0).

Coupled with the fact that bash numeric comparison operators observe following behavior:

If numeric comparison is satisfied, exit code shall be 0. Else, exit code shall be 1. To illustrate:

$ [ 1 -gt 10 ]; echo $?
1
$ [ 11 -gt 10 ]; echo $?
0

Therefore, the original script could be revised to:

while true
do
    FILE_COUNT=`ls -1tr $MY_DIR/temp.log.* | wc -l`

    [ $FILE_COUNT -gt $MAX_FILE_COUNT ] && _delete_oldest_file
done

This is especially helpful if I have a flow involving many steps. Let's consider I have a 3 steps flow such that:

  1. Run _do_A()
  2. Run _do_B() if _do_A() is successfully executed
  3. Run _do_C() if _do_B() failed to execute

Without the help of chaining operators, I likely need 3 if checking to deliver the flow. But with the help of chaining operators:

_do_A() && _do_B() || _do_C()

Elegant. Isn't it? 😎

Now, let's imagine we have a 10 steps flow. Isn't that chaining operators a life savior?

Top comments (0)