Bash Options
You can set bash option in two ways, with shopt or with set command. For example:
shopt -s extglob
set -o nounset
Here is a list of options. I often use “set -e” right after shebang to tell the script to exit upon failed command, because the rest of the script will be error-prone after the failed command. I can use “set +e” to negate the flag.
Also, we can use the unset command to delete the variables during program execution, or the export command to export a variable or function to the environment of all the child processes running in the current shell.
User menu and argument processing
It is a common task in bash scripting to display user menu or process argument. Both use case structure. Here are the examples:
User menu:
#! /bin/bash
select car in BMW TOYOTA TESLA
do
case $car in
BMW)
echo "X3";;
TOYOTA)
echo "Camry";;
TESLA)
echo "Some";;
*)
echo "Unknown";;
esac
done
Argument processiong example:
#! /usr/bin/bash
while getopts ":ht" opt; do
case ${opt} in
h ) echo "option h"
;;
t ) echo "option t"
;;
\? ) echo "Usage: cmd [-h] [-t]"
;;
esac
done
Try to run the script with the following options:
$ test.sh -t
$ test.sh -h
$ test.sh -ht
$ test.sh -th
$ test.sh -a
Build-in commands declare, local, let, eval
The declare command allow you to assign an attribute to a variable. For example:
- -a indexed array
- -A associative array
- -i integer
- -r read only
The local descriptor declare a variable that is only effective in the code block. For example, within the function.
With command let, each arg is taken as arithmetic expression:
$ A=1
$ B=2
$ let sum=$A+$B
$ echo "A=$A, B=$B, C=$C"
$ A=1, B=2, C=3
With command eval, each arg is taken as a string:
$ A=1
$ B=2
$ eval sum=$A+$B
$ echo "A=$A, B=$B, C=$C"
A=1, B=2, C=1+2
Commands trap and inotifywait
The trap command that you can use to catch signals from script and execute code. For example:
trap "info 'caught interrupt, will stop'; exit 2" INT
Inotify is a file system monitoring mechansim. The inotifywait can be used in many complex scenarios. It requires inotify-tools package. As an example, the following snippet use inotifywait to montor a directory, and trigger rsync upon changes
#!/bin/bash
DESTHOST=172.17.23.132
DESTHOSTDIR=/www/htdocs/
SRCDIR=/www/htdocs/
inotifywait -mr --timefmt '%d/%m/%y %H:%M' --format '%T %w %f' \
-e create,delete,modify,attrib $SRCDIR | while read DATE TIME DIR FILE; do
$FILECHANGE=${DIR}${FILE}
rsync -avze 'ssh' $SRCDIR root@${DESTHOST}:${DESTHOSTDIR} &>/dev/null && \
echo "At ${TIME} on ${DATE}, file $FILECHANGE was backed up via rsync" >> /var/log/filesync.log
done
The example above shows how to copy a file to a remote server upon change. There is a simpler alternative to it, a tool called lsyncd, which combines rsync and inotify. lsyncd is a linux package (can be installed with yum) and remains an open source project.
The configuration is done in LUA language. Here is a simple example:
settings {
logfile = "/var/log/lsyncd/lsyncd.log",
statusFile = "/var/log/lsyncd/lsyncd.stat",
statusInterval = 1
}
sync{
default.rsyncssh,
source="/etc/dhunch/",
host="remote-host",
targetdir="/etc/dhunch/",
delay = 10,
exclude={'*.bak',
'*.tmp',
'deploy.log',
'themes/'},
rsync={
checksum=true,
times=true,
chown="hunch:hunch",
chmod="755"
}
}
In this example, we tell lsyncd to use rsyncssh mechanism and it can use hosts defined in openssh configuration (e.g. ~/.ssh/config). For more than one hosts, we can declare the sync section more than once. Full documentation is here.