The Lab Book Pages

An online collection of electronics information

http://www.labbookpages.co.uk

Dr. Andrew Greensted
Last modified: 17th September 2010

Hide Menu


Valid XHTML Valid CSS
Valid RSS VIM Powered
RSS Feed Icon

This site uses Google Analytics to track visits. Privacy Statement

Page Icon

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.


Script variables

Bash has some useful built in 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 run in the background)
$? The exit status of the last command
$# The number of command line arguments passed to script

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 code 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

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 '-> ' (hyphen, greater-than, space).

FILE_NAME=/file/somewhere

LS_OUT=$(ls -l "$FILE_NAME")
TARGET=${LS_OUT#*-> }

Another, simpler solution, suggested by Paul Donohue, is to use the readlink command. This seems to be a much more robust approach.

> readlink -f /path/to/a/symlink

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

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 lock file test and creation (if needed) to be atomic, that is done without interruption. The set -C stops a redirection from over writing 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 lock file 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

Mount Test

This example is useful for testing if a mount-point is mounted. The output 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

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

Book Logo