Index

Table of contents

Basic script necessities

parse command line arguments

parse arguments using simple case statement
usage() {
        echo usage: `basename $0` '[-a] [-o arg] [file]...' 1>&2
        exit 1
}

while true
do
	case "$1" in
	        -a) a=1;;
        	-o) shift; o="$1";;
	        -*) echo "unknown flag $1" 1>&2; usage;;
        	*) break;;
	esac
shift
done

echo "a=$a"
echo "o=$o"
echo "remaining: $@"
use getopt for more flexible interface (e.g. supports composite flags)
usage() {
        echo usage: `basename $0` '[-abc] [-o arg] [file]...' 1>&2
        exit 1
}

set -e
parsed=`getopt "abco:" "$@"` || usage
set -- $parsed

while true
do
        case "$1" in
	        -a) a=1;;
        	-b) b=1;;
	        -o) shift; o="$1";;
        	--) shift; break;;
        esac
        shift
done

echo "a=$a"
echo "b=$b"
echo "o=$o"
echo "remaining: $@"
documentation
https://www.tutorialspoint.com/unix_commands/getopt

utility functions

utility method for exiting scripts
die() {
	echo >&2 "$@"
	exit 1
}

common checks

check syntax of file before running
set -e
sh -n `basename $0`
request root privileges from script (will replace process)
[ $(id -u) -eq 0 ] || exec sudo "$0" "$@"
require root privileges (sudo or root)
if [ "$(id -u)" != "0" ]; then
        die "root privileges required!"
fi
block root user and also block running with sudo
if [ "$(id -u)" = "0" ]; then
        die "run this script as a normal user!"
fi
user "root" cannot run this script, but sudo works
if [ "$HOME" = "/root" ]; then
       die "do not run script as root, use sudo!"
fi
script input validation => exactly 2 arguments
[ "$#" -eq 2 ] || die "2 arguments required: [ARG1] [ARG2]"
script input validation => at least 3 arguments
[ "$#" -ge 3 ] || die "3 arguments required: [ARG1] [ARG2] [ARG3]"
verify file size is at least
file=$1
minimumsize=$2
actualsize=$(wc -c <"$file")
if [ $actualsize -ge $minimumsize ]; then
    echo size is over $minimumsize bytes
else
    echo size is under $minimumsize bytes
fi
verify zip file integrity
unzip -t $ARTIFACT_NAME || die "invalid zip file!"
verify port is available
set +e
nc -z -w1 localhost 8080
if [ "$?" -eq 0 ]; then
    echo "port 8080 is not available!"
else
    # $? will be 1
    echo "port 8080 is in use!"
fi

variables

ternary oprator imitation (note: non zero exit status -> false)
myvar=$([ expression ] && echo "true" || echo "false")
[ expression ] && myvar="true" || myvar="false"
fill a variable from the system input
read [name]
echo "read $[name]"
read variable from same line as printed prompt
read -p "enter name: " var
echo "hello $var"
increment variable
count=$((count + 1))
count=$(echo "$count + 1" | bc)
generate a random number between 0 and 99
ran=$(shuf -i 0-99 -n 1)
variable with date
LOGFILE=/var/log/installer_$(date +%y-%m-%d_%T).log
last modification date of file
mod=$(stat -c '%Y' [file])
extract substring matching regex in variable
a=$(echo "abc" | grep -Eo '.b')
a=$(expr 'abc' : '\(.\)b')
pass all command line arguments to another script
java com.myserver.Program "$@"

tests

not
if [ ! "$1" = "" ]; then
and
if [ "$1" != "" -a "$2" = "" ]; then
or
if [ "$1" != "" -o "$2" = "" ]; then
check if is a directory
if [ -d "links" ]; then
    echo "directory exists"
fi
check if a directory does not exist
if [ ! -d "links" ]; then
    echo "directory does not exist"
fi
fail if it does not (function die defined above)
[ -d "$SOURCE_ROOT" ] || die "$SOURCE_ROOT is not a directory"
check if a directory exists and has contents (-a to check for hidden files)
if [ "$(ls -A $dir 2> /dev/null)" != "" ]; then
if [ "$(ls -aA $dir 2> /dev/null)" != "" ]; then
check if is ordinary file
if [ -f /tmp/file ]; then
    echo "is a regular file"
fi
verify file is not empty
if [ -s "$_file" ]
then
    echo "$_file has some data."
else
    echo "$_file is empty."
fi
check if $VARIABLE refers to a soft link
if [ -L "$VALUE" ]
check if $VALUE exists on the filesystem (can be a file, directory, link, etc.)
if [ -e "$VALUE" ]
check for output
if [ "$(ls -lA)" != "" ]; then
  echo "process has output"
if [ ! -z "$(ls -lA)" ]; then
  echo "process has output"
require string is empty
if [ -z "$foo" ]; then
        echo empty
fi
require value (not empty)
if [ "$pid" ]; then
        echo pid has a value
fi
checking the contents of a string
if [ "$test" = "false" ]; then
       echo "tests off"
fi
checking whether or not a string contains a substring
case "$var" in
    *[substring]*) echo "match";;
    *)             echo "mis"  ;;
esac
checking a string against a regular expression
if echo "$test" | grep -qE '[regex]'; then
        echo regex match
fi

Config file

contents of a config file
config_dir=/path/to/dir
config_file="$config_dir/path/to/file"
load a file with config settings (dot space config file)
. settings.cfg
after reading the config file, the variables are available in the script

documentation

https://wiki.bash-hackers.org/commands/classictest
http://cis.stvincent.edu/html/tutorials/unix/bshellref
http://tldp.org/LDP/abs/html/comparison-ops.html
https://en.wikibooks.org/wiki/Bourne_Shell_Scripting/Control_flow

linux commands useful for scripting

basename = get the basename of a file (drop extension)