Standardizing Scripts
http://mirror.aarnet.edu.au/linux/LDP/HOWTO/Adv-Bash-Scr-HOWTO/index.html
Notes:
Bash v2 scripting uses strings differently. Within your comparison
statements with strings, use an x or something instead of making it a
blank or stand-alone string. An example follows:
if [ "x$pf" != x"NO" ]; then
if [ x"${ipfilter}" = x"YES" -a -f "${ipfilter_rules}" ]; then
Redirects:
1> filename - redirects STDOUT to filename (erases file contents)
> filename
1>> filename - redirects STDOUT to filename (appends to file)
>> filename
2> filename - redirects STDERR to filename
1>&2 - redirects output to STDERR
>&2
2>&1 - redirects STDERR to STDOUT
The '&' redirects to the number following it.
< filename - inputs filename contents to a command:
cat filename or cat < filename
>| - Force Redirection, forcibly overwrites an existing
file even if 'noclobber env variable is in effect.
- - Redirection from/to STDIN or STDOUT
This option is not an option of sh but an option
of utilities to alias a filename with STDOUT.
-----------------------------------------------------------------------------
Script Variables:
$0 - The filename of the script.
$1 - The first command line argument.
$n - The (n)th command line argument.
$@ - Array of command line arguments (quoted / not expanded).
$# - The number (integer) of command line arguments.
$* - List of command line arguments.
$$ - The Process ID (PID) of the script.
$? - Exit status of last command, function, or script.
$- - Flags passed to script.
$! - PID of last job run in background (job &).
ls | grep "file_name.ext"
if [ ! "$?" = "0" ]; then
echo "file_name.ext not found"
fi
/sbin/pidof pppd >/dev/null 2>&1; PPPDQ="$?"
if [ "$PPPDQ" = "0" ]; then
killall pppd
fi
-----------------------------------------------------------------------------
Environment Variables:
$FILE=
$FILE="/bin/sh"
echo $FILE
$NUM=
$NUM=1
$NUM=`expr $NUM + 1`
-----------------------------------------------------------------------------
Using /bin/echo:
To use the output of a command:
echo "This system is: `uname -a`"
To echo data but not a carriage return, use the -n switch:
echo -n "No line return after this!"
To ring the system bell, use the -e switch:
echo -e "\a"
The -e switch has makes echo interpret escape sequences
such as \n \t \a \\, etc. For more help on this:
% man echo
-----------------------------------------------------------------------------
Statements:
The opening bracket '[', is an alias for test, in theory, it is
not necessary for the closing bracket ']' but newer versions of
bash will complain if it is omitted.
if [ -f /bin/sh ]; then
echo "You have the /bin/sh shell."
elif [ -f /bin/bash ]; then
echo "You have the /bin/bash shell."
else
echo "The else statement."
fi
if [ ] && [ ]; then
...
fi
if [ ] || [ ]; then
...
fi
[ -f /etc/spcsys ] && echo /etc/spcsys is present.
[ ! -f /etc/spcsys ] || echo /etc/spcsys is present.
if [ -f /etc/spcsys1 -o -f /etc/spcsys2 ]; then
echo "OR is true"
fi
if [ -f /etc/spcsys1 -a -f /etc/spcsys2 ]; then
echo "AND is true"
fi
if [ $# = "0" ]; then
echo "No arguments"
elif [ $# = 1 ]; then
echo "1 argument: $1"
else
shift # removes $1 from stack.
echo "${@-}" # echoes all other arguments.
fi
case ${file} in
*.gif|*jpg)
echo "${file}: graphic file"
;;
*.txt|*.tex)
echo "${file}: text file"
;;
*)
echo "${file}: generic file"
;;
esac
case `cat file.ext` in
*string*)
echo "It exists"
;;
*)
echo "It does not exist"
exit 0
;;
esac
case `ping -qnc some.machine.net` in
*'100% packet loss'*)
echo "The network is down."
echo
exit 0
;;
esac
case `ping -qnc 1 www.yahoo.com` in
*'100% packet loss'*)
echo "The network is DOWN."
echo ""
exit 1
;;
*)
echo "The network is UP."
echo ""
;;
esac
# case with regular expressions:
echo -n "Enter a key and hit enter"; read k
case "$k" in
[a-z]) echo "lowercase letter";;
[A-Z]) echo "Uppercase letter";;
[0-9]) echo "Number";;
* ) echo "Non character";;
esac
-----------------------------------------------------------------------------
Loops:
for { variable name } in { list }
do
...
done
for i in 1 2 3 4 5
do
echo "Welcome $i times"
done
for NAME in hamish heidi matthew riaan simone
do
echo "people involved in this project: "
echo $NAME
done
for file in `ls .` ; do
echo "${file}"
...
done
for var in /dev/ttyS[1-9]*; do
echo $var
done
# Loop over the command-line arguments:
# Note: The $* argument will fail if spaces exist.
for filename in "$@"; do
echo "$filename"
done
# If 'in' is omitted, for works on '$#'
for i; do
echo $i
done
for (( start value; comparison; count increment ))
for (( expr1; expr2; expr3 ))
do
repeat all statements between do and
done until expr2 is TRUE
done
for (( i = 0 ; i <= 5; i++ ))
do
echo "Welcome $i times"
done
for ((i=0; i<=10; i=i+1)) #can replace i=i+1 with i++
do
echo $i
done
count=1
for arg
do
echo "Argument $count is $arg"
$((count=count+1)) #or: count=$((count+1)) or: count=`expr $count + 1`
: $((count=count+1)) #prevents error message where it is looking to execute the number (: = noop)
done
for i in `seq 20`
do
echo $i
done
---------------------------------------------------------------------
while [ $i -lt 10 ]; do
...
i=`expr $i + 1`
done
cat $0 | while read line; do
echo $line
done
---------------------------------------------------------------------
until [ $i -gt 10 ]; do
...
i=$(($i+1))
done
---------------------------------------------------------------------
contine and break
while [ condition ]; do
...
if [ condition ]; then
continue [or break]
fi
...
done
-----------------------------------------------------------------------------
Pipes:
To pipe the entire output stream of a set of commands into
a single application, use '() |'. Example:
(
echo "To: hostmaster "
echo "From: system "
echo "Subject: Anything"
...
) 2>&1 | /usr/lib/sendmail -t
-----------------------------------------------------------------------------
The colon symbol ":" (null command) is an alias for true. For example,
it can be used for an endless loop:
while : ; do
...
done
A colon may also be used as a placeholder in an if/then test:
if condition
then : #do nothing and branch ahead
else
...
fi
A colon may be used to evaluate variables using "parameter substitution":
: ${HOSTNAME?} ${USER?} ${MAIL}
# prints an error message if one or more not set.
-----------------------------------------------------------------------------
Reading STDIN:
echo "Are you in a good mood? [y,n]"
read ans
if [ "$ans" = y ]; then
echo "Good!"
elif [ "$ans" = n ]; then
echo "Sorry!"
else
echo "Error: Bad option"
fi
-----------------------------------------------------------------------------
Special Characters And Syntax:
${} - Parameter Substitution
To strip off the shortest/longest part of a 'pattern' if it
matches the front end of 'var':
${var#pattern} / ${var##pattern}
To strip off the shortest/longest part of 'pattern' if it
matches the back end of 'var':
${var%pattern} / ${var%%pattern}
Example of renaming file extensions, to rename all .gif
files to .jpg files:
# ./script gif jpg
for filename in *.$1; do
mv $filename ${filename%$1}$2
done
-------------------------------------------------------------
${var:pos}
'var' expanded, starting from offset 'pos'.
${var:pos:len}
'var' expanded to a max of 'len' characters.
${var/pattern/replace}
First match of 'pattern', within 'var' replaced
with 'replace'. If 'replace' is omitted, the first
match of 'pattern' is stripped or deleted.
${var//pattern/replace}
All matches of 'pattern', within 'var' are replaced
with 'replace'. If 'replace' is omitted, all matches
of 'pattern' are stripped or deleted.
---------------------------------------------------------------------
/{} - File Pathname, used mostly in 'find' constructs
---------------------------------------------------------------------
() - Command Group
Commands enclosed within parentheses starts a subshell.
---------------------------------------------------------------------
{} - Block of Code
Creates an anoymous function, the code block enclosed
in braces may have I/O redirected to and from it.
{
read fstab
} < /etc/fstab
echo "First line in /etc/fstab is:"
echo $fstab
-----------------------------------------------------------------------------
Bash Internal Commands:
getopts - parses command line arguments passed to a script.
The argument must be proceeded with either a '-' or
a '+'.
while getopts ":mnopq:rs" option; do
# the ':' after q shows it will have an option after it.
case $option in
m) ... ;;
q) echo $OPTARG ;;
...
esac
done
shift $(($OPTIND - 1))
The
---------------------------------------------------------------------
basename
- strip path from filename.
basename /bin/ls
dirname
- strip basename from filename.
dirname /bin/ls
factor
- factor an integer into prime factors.
factor 1024
hash[cmds]
- Record the path name of specified commands. When
hash is called with no arguments, it lists hashed
commands.
wait
- stop script execution until all background processes
finish.
suspend
- same as control-z [^z].
stop
- same as suspend but for background processes.
times
- gives statistics on the system time used in executing
commands.
000000*
-----------------------------------------------------------------------------
Typing Variables: declare or typeset:
declare [option flag] variable_name
option flags:
-r - readonly
-i - integer
-a - array
-f - functions
# no arguments will list all functions.
declare -f
-x - export
-----------------------------------------------------------------------------
Arithmetic:
To perform simple arithmetic, use the 'expr' command.
x=24
y=04
result=$(expr $x \* $y)
echo "$x times $y is $result"
let a=16+5
i=1 ; z=10
while [ $i -le $z ]; do
echo $RANDOM
let "i += 1"
done
-----------------------------------------------------------------------------
Using AWK:
The AWK command is used to read and print formatted text such
as tables seperated by whitespace.
ls -al | awk '{print $5}'
ls -al | awk '{sum = sum + $5} END {print sum}'
-----------------------------------------------------------------------------
Using sed (Stream Editor):
The sed utility reads the specified files, or the standard input if
no files are specified, modifying the input as specified by a list
of commands. The input is then written to the standard output.
To remove blank lines in a file:
sed -e /^$/d filename
To substitute one pattern for another:
sed -e "s/old_pattern/new_pattern/" filename