Switch to Normal Style Sheet
Site Icon The Lab Book Pages Andrew Greensted (Modified: 17 June 2008)
Software > Bash Tips

Bash Tips

Here is a list of useful scripting (mainly bash oriented) tricks. For a really good source of bash info check out the Advanced Bash Scripting Guide. The code blocks were generated using vim's rather handy 2HTML command.

Divider Bar Go to page top

• Script variables

Bash has some useful builtin variables. Here is a table of a few.

Variable Description
$$ The PID of the script
$! The PID of the command that has just been executed (and backgrounded)
$? The exit status of the last command
$# The number of command line arguments passed to script
Divider Bar Go to page top

• Command Checker

It's generally a good idea to check that a script has access to all the commands it uses before it starts doing its stuff. The little codelet below can be used to do that. It loops through an array of command names and checks they are available using the type command.

The type command is used to check if the command is in the path. The &> is used to redirect the output of type to /dev/null so that it is not displayed on the terminal.

# Test that required commands are in the path
for CMD in rsync awk grep mount df; do
   type $CMD &> /dev/null

   if [ $? != "0" ]; then
      echo "The command '$CMD' is required and is not in your path"
      exit 1
   fi

done
Divider Bar Go to page top

• Finding Symbolic Link Target

These simple commands can be used to find the target of a symbolic link. The first part simply gets a listing of the file, including the target file. The second part is used to strip away the file part of the string, leaving the target part.

Note: This fails if the link name contains the characters '-> ' (hypen, greater-than, space).

FILE_NAME=/file/somewhere

LS_OUT=$(ls -l "$FILE_NAME")
TARGET=${LS_OUT#*-> }
Divider Bar Go to page top

• Colourised Output Control

Colour really can make the output of a script easier to read. Here's some helpful bits to achieve that. The -e flag on the echo command makes it interpret the escaped characters properly.

ESC_SEQ="\x1b["
COL_RESET=$ESC_SEQ"39;49;00m"
COL_RED=$ESC_SEQ"31;01m"
COL_GREEN=$ESC_SEQ"32;01m"
COL_YELLOW=$ESC_SEQ"33;01m"
COL_BLUE=$ESC_SEQ"34;01m"
COL_MAGENTA=$ESC_SEQ"35;01m"
COL_CYAN=$ESC_SEQ"36;01m"

echo -e $COL_BLUE"INFO: "$COL_RESET"This is an info message"
echo -e $COL_RED"An error has occured"$COL_RESET
Divider Bar Go to page top

• Force Non-Concurrent Execution

So, you've got a script that you only want a single instance of running at a time? This might help.

The clever bit is to get a lockfile test and creation (if needed) to be atomic, that is done without interruption. The set -C stops a redirection from overwritting a file. The : > touches a file. In combination, the effect is, when the lock file exists, the redirection fails and exits with an error. If it does not exist, the redirection creates the lock file and exits without an error.

The final part is to make sure that the lockfile is cleaned up. To makes sure it is removed even if the script is terminated with a ctrl-c, a trap is used. Simply, when the script exits, the trap is run and the lock file is deleted.

LOCK_FILE=/tmp/.lock

(set -C; : > $LOCK_FILE) 2> /dev/null
if [ $? != "0" ]; then
   echo "Lock File exists - exiting"
   exit 1
fi

trap 'rm $LOCK_FILE' EXIT

# Do useful stuff
Divider Bar Go to page top

• Mount Test

This example is useful for testing if a mount-point is mounted. The ouput of mount is fed into awk which is used to filter out all but text in the third column (that's where the info on mount-points is held). Then, if a line that contains the mount-point is found, it is printed. This can then be used with a normal bash test.

It can also be tweaked to test if a device is mounted, just changed the test column from 3 to 1.

MNT_POINT=/backup

MNT_INFO=$(mount | awk -v mnt=$MNT_POINT '{ if ($3 == mnt) print $0 }')

if [ "$MNT_INFO" == "" ]; then
	echo "Not Mounted"
else
	echo "Mounted"
fi
Divider Bar Go to page top

• Root Check

Sometime it is useful to determine if a script is being run as root or not. A simple check can be performed at the start of a script before anything important is done. The bit of code below will do this.

# Check the script is being run by root
if [ "$(id -u)" != "0" ]; then
   echo "This script must be run as root"
   exit 1
fi
# Check the script is not being run by root
if [ "$(id -u)" == "0" ]; then
   echo "This script must not be run as root"
   exit 1
fi
Divider Bar Go to page top