CS246-F20-01-UnixShell
Lecture 1.15
• Writing bash scripts
– shift, if, case
CS246
shift
• shift [N] destructively shifts (“eats”) parameters to the
left N positions
i.e., ${1}=${N+1}, ${2}=${N+2}, …,
also, ${#} is reduced by N
– If no N, 1 is assumed.
– If N is 0 or greater than ${#}, there is no shift (but it’s not an error)
$ cat shiftIt
#!/bin/bash
echo ${1}; shift 1
echo ${1}; shift 2
echo ${1}; shift 3
echo ${1}
$ ./shiftIt 1 2 3 4 5 6 7 8 9
1
2
4
7
• shift is often used in a shell script to process command line
args before doing the “real work”
– Usually no presumed ordering on command line options; these two are
both legal and mean the same:
ssh –Y –l cs246 linux.cs.uwaterloo.ca
ssh –l cs246 –Y linux.cs.uwaterloo.ca
– How would we process this? What would the logic look like?
shift if
• Two (awkward) syntaxes (prefer the first, with “;”):
if
elif
…
else
fi
if
then
elif
then
…
else
fi
• testCommand is evaluated; exit status of zero implies true,
otherwise false
if test “$(whoami)” = “jfdoe” ; then
echo “Hi JF!”
else
echo “Hello user, whose name I don’t know”
fi
if diff file1 file2 > /dev/null ; then # ignore diff output
echo “same files”
else
echo “different files”
fi
if [ -x /usr/bin/cat ] ; then # alternative syntax
echo “/usr/bin/cat command available”
else
echo “no executable cat in /usr/bin, look somewhere else?”
fi
Some gotchas
• As we learned earlier, if a shell variable has no value, bash
returns the empty string when you dereference it
i.e., it is not flagged as an error, as in tcsh
– This can cause scripts to break, and you may not get a very good
indication of what went wrong, exactly
• Also, when you deference a variable, surround it in quotes or
the shell may try to process incorrectly
$ v=”yes”
$ [ $v = yes ]
$ echo $?
0
$ unset v # v has no value now
$ [ $v = ‘yes’ ] # if [ = ‘yes’ ]
bash: [: =: unary operator expected
$ v=”a b c”
$ [ $v = ‘yes’ ] # if [ a b c = ‘yes’ ]
bash: [: too many arguments
$ unset v
$ [ “$v” = ‘yes’ ] # if [ “” = ‘yes’ ], legal
$ v=”a b c”
$ [ “$v” = ‘yes’ ] # if [ “a b c” = ‘yes’ ], legal
• A case statement selectively executes one of N alternatives
based on matching a string expression with a series of
patterns (globbing)
case expression in
pattern | pattern | . . . ) commands ;;
…
* ) commands ;; # optional match anything
esac
– When a pattern is matched, the corresponding commands are
executed up to “;;”, and control exits the case stmt
• There is no “fall through” with “;;” like in C/C++/Java
– If no pattern is matched, the case statement does nothing
case
#!/bin/bash
# options: -h, –help, -v, –verbose, -f file, –file file
usage() {
echo “${0} [-h, –help, -v, –verbose, -f file, –file file]”
exit 1 # print message and terminate script
}
verbose=no
case “${1}” in # process single option
‘-h’ | ‘–help’ ) usage ;;
‘-v’ | ‘–verbose’ ) verbose=yes ;;
‘-f’ | ‘–file’ ) # has additional argument
shift 1 # access argument
file=”${1}”
;;
* ) usage ;; # default, has to be >= one argument
esac
if [ “$verbose” = “yes” ] ; then
echo “I can never visit Philadelphia without being reminded …”
elif [ “$file” != “” ] ; then
echo ${file}
fi
End
CS246