Americas

  • United States
sandra_henrystocker
Unix Dweeb

Bash scripting tips that can save time on Linux

How-To
Feb 20, 20236 mins
Linux

Here are steps you can take to ensure that your bash scripts work as intended and are easy to update.

computer command screen blurred
Credit: Shutterstock / Media Whalestock

Committing routine and even rarely required tasks to scripts is almost always a big win because you don’t have to reinvent the approach to getting work done each time it’s needed, and you save a lot of time on issues you handle often.

Here are some tips for writing bash scripts and ensuring that they’ll be easy to use, easy to update/ and hard to misuse.

Comments

One important thing to do when you’re preparing a script on Linux is to add comments – especially for commands that might be a little complex. If you don’t run a script very often, comments can help ensure that you quickly grasp everything that it’s doing. If someone else has to use your scripts, the comments can make it a lot easier for them to know what to expect. So, always add comments. Even you might appreciate them! You don’t need to comment every line, just every significant group of commands. Here’s a simple example.

#!/bin/bash

# function to replace spaces in provided text with underscores
replspaces () {
  echo $@ | sed 's/ /_/g'
}

# function to remove spaces from the provided text
dropspaces () { echo $@ | sed 's/ //g'; }

# commands to call the functions defined above
replspaces "Hello World"
replspaces `date`
dropspaces "Hello World"
dropspaces `date`

The script above defines two functions: one to turn spaces into underscores and one to remove spaces altogether in whatever string is provided at the prompt. The comments say enough to explain this.

Using functions

As noted in the script above, functions can come in handy. This is especially true when a single script will run the functions many times. The scripts will be shorter and will be easier to understand.

Verifying arguments

Make a habit of having your scripts verify that the proper arguments have been provided by whomever runs them. You can check the number of arguments, but you can also verify that the responses are valid. For example, if you prompt for the name of a file, check that the file provided actually exists before running commands that attempt to use it. If it doesn’t exist, respond with an error and exit.

The script below checks to ensure that two arguments have been provided as arguments to the script. If not, it prompts for the information needed.

#!/bin/bash

if [ $# -lt 2 ]; then
    echo "Usage: $0 lines filename"
    exit 1
else
    numlines=$1
    filename=$2
fi
…

The script below prompts for a filename and then checks to see if the file exists.

#!/bin/bash

# get name of file to be read
echo -n "filename> "
read $filename

# check that file exists or exit
if [ ! -f $filename ]; then
    echo "No such file: $filename"
    exit
fi

If needed, you can also check whether the file is writable or readable. The version of the script below does both.

#!/bin/bash

# get name of file to be read
echo -n "filename> "
read filename

# check that file exists or exit
if [ ! -f $filename ]; then
    echo "No such file: $filename"
    exit
else # determine if file is readable
    if [ ! -r $filename ]; then
        echo "$filename is not writable"
        exit
    fi
    # determine if file is writable
    if [ ! -w $filename ]; then
        echo "$filename is not readable"
        exit
    fi
fi

Note: The -r $filename check asks whether the file is readable. The ! -r $filename check asks whether it’s not readable.

Exiting on errors

You should almost always exit when an error is encountered when a script is run. Explain with an error message what went wrong. The set -o errexit will cause a script to exit regardless of what kind of error is encountered.

#!/bin/bash

set -o errexit  # exit on ANY error

tail NoSuchFile # tries to show bottom lines in NON-EXISTENT file
echo -n "Enter text to be appended> "
read txt
echo $txt >> NoSuchFile

The script above will exit if the “NoSuchFile” file doesn’t exist. An error will be displayed as well.

To exit when a variable hasn’t been assigned a value (i.e., doesn’t exist), use the nounset option as shown in the script below. A set -u command works the same.

#!/bin/bash

# exit script if an unset variable is used
set -o nounset

# welcome user with a greeting
echo $greeting

echo -n "Enter name of file to be evaluated: "
read filename

If you run the script as is, you’ll run into the issue shown below and never be prompted for the file to be processed:

$ ck_nounset
./ck_nounset: line 7: greeting: unbound variable

Working with quotes

In a lot of cases, it doesn’t matter if you use single quotes, double quotes, or no quotes at all. Putting quotes around a variable name in an if statement means that you won’t run into an error if the variable is not defined. The shell will never end up trying to evaluate the invalid command if [ = 2 ]. The command if [ “” = 2 ] is valid.

if [ "$var" = 2 ]

Putting quotes around arguments with more than one string is essential. You’d run into problems with the script below if the user answering the good/bad question entered “very good” instead of just “good” or “bad”.

#!/bin/bash

echo -n "Did you find the argument to be good or bad?> "
read ans

if [ $ans = good ]; then
  echo "Thank you for your feedback"
else
  echo -n "What didn't you like?> "
  read ans
  echo $ans >> bad_feedback
fi

Instead, you could use a line like this to do the comparison. This would allow either “good” or “very good” as a response.

if [[ "$ans" = *"good" ]]; then

Using = or ==

Most of the time it makes no difference whether you use = or == to compare strings. However, some shells (e.g., dash) don’t work with ==, so save yourself the keystrokes and stick with = if you’re not sure.

File permissions

Make sure your scripts can be run by anyone who should be able to use them. A chmod -ug+rx filename command would give you (presumably the file owner) and anyone in the group associated with the file the ability to read and run the script.

Test your scripts

Don’t forget to spend some time testing to make sure your scripts do exactly what you intend. Testing can include things like failing to respond to the script’s prompts to see how it reacts.

sandra_henrystocker
Unix Dweeb

Sandra Henry-Stocker has been administering Unix systems for more than 30 years. She describes herself as "USL" (Unix as a second language) but remembers enough English to write books and buy groceries. She lives in the mountains in Virginia where, when not working with or writing about Unix, she's chasing the bears away from her bird feeders.

The opinions expressed in this blog are those of Sandra Henry-Stocker and do not necessarily represent those of IDG Communications, Inc., its parent, subsidiary or affiliated companies.