CS246-F20-01-UnixShell
Lecture 1.13
• Writing bash scripts
– Basics, command-line parameters, routines
CS246
Scripting UNIX with bash
• We’ve introduced you to basic concepts and commands of the
UNIX shell bash
– We’re going to build up your knowledge of how the shell works so that
you can create executable programs out of these building blocks
• A reasonable alternative (that we did not choose to pursue)
would be to learn a scripting language, like Python, Ruby, …
– These have the advantage of being portable across difference
operating systems
– UNIX shell scripts don’t work outside of UNIX, tho bash has been
ported to Windows10 (and bash exists in OSX because OSX is UNIX
underneath)
• A shell script is a file containing shell commands to be executed:
#!/bin/bash
# Some shell and OS commands
date
whoami
echo “Hi there”
• First line should begin with magic comment: “#!” (sha-bang,
hash-bang, etc.) with shell pathname for executing the script.
– It forces a specific shell to be used, which is run as a sub-shell of the
invoking shell
– If the “#!” line is missing, a sub-shell of the same kind as the invoking
shell is used for sh shells (bash) and sh is used for csh shells (tcsh)
Shell scripts
Let’s save this in a file called
myFirstBashScript
Shell scripts
• Optional -x on first line prints trace of the script as it executes:
#!/bin/bash –x
… # rest as before
• We can either execute the file by calling bash:
$ bash myFirstBashScript
• … or (better) make the file executable, and call it as a command:
$ chmod a+x myFirstBashScript
$ ./myFirstBashScript
Thu 13 Sep 2012 09:50:58 EDT
migod
Hi there
• When you call a shell script on the command line, you can provide
parameters too
– And inside the script, you can access them via special parameter
variables:
#!/bin/bash
echo “My $3”
$ ./myScript Hello my “true friend”
My true friend
$ ./myScript Hello my true friend
My true
$ ./myScript Hi there
My
Shell script parameters
Let’s save this in a file called
myScript and make it executable
Shell script parameters
${#} # of args, not including script name
${0} name of shell script (file)
${1}, ${2}, … refers to arguments by position (not name),
i.e., 1st, 2nd, 3rd, arg
${*} or ${@} list all arguments, e.g., ${1} ${2} . . .,
not including script name
“${*}” args as a single string,
e.g., “${1} ${2} . . .”
“${@}” args as separate strings,
e.g., “${1}” “${2}” . . .
${$} process id of executing script [advanced]
${?} exit status of the last command executed;
0 often means “exited normally”
$ cat scriptfile
#!/bin/bash
echo ${#} # number of command-line arguments
echo ${0} ${2} ${4} # print some of the arguments
echo “${*}” # all arguments as a single string
echo “${@}” # all arguments as separate strings
echo ${$} # process id of executing sub-shell
exit 21 # script exit status
$ ./scriptfile a1 a2 a3 a4 a5
5
scriptfile a2 a4
a1 a2 a3 a4 a5
a1 a2 a3 a4 a5
27028
$ echo ${?} # print script exit status
21
More on (bash) shell scripts
• A shell script written for bash will look different from one written
for sh or tcsh
– The syntax and supported features are slightly different for each shell,
even tho they interact with the same UNIX programs (in /usr/bin, etc.),
and the same file system
– Environment variables can be shared (and inherited) between different
kinds of shells too
• Tho we won’t look at this topic
• Like most programming languages, bash supports selection (if),
repetition (loops), variables, and the definition of reusable routines
– We will now examine these features in turn
– Really, you just need to learn the (annoying, odd) syntax here; there isn’t
much intellectually challenging about this
$ cat isItAWord
#!/bin/bash
egrep “^$1$” /usr/share/dict/words
$ chmod a+x isItAWord
$ ./isItAWord flurble # no output if not found
$ ./isItAWord floor
floor
$ cat checkPassword
#!/bin/bash
egrep “^$1$” /usr/share/dict/words > /dev/null
# Note: redirecting stdout to /dev/null suppresses output
# Note: every program returns a status code when finished
# egrep returns status code 0 if found, 1 if not found
# (in UNIX: 0 = success, non-zero = failure)
# $? = status of most recently-executed command (ie, egrep)
if [ $? -eq 0 ]; then
echo Bad password
else
echo Maybe a good password
fi
$ ./checkPassword secret
Bad password
$ ./checkPassword fluRBlez8#8
Maybe a good password
• A routine is defined inside a script as follows:
flurble () { # of params depends on actual call
# some set of commands
}
• Invoke like a command inside the script
flurble [ args … ]
e.g., create a routine to print incorrect usage-message
usage() {
echo “Usage: ${0} -t -g -e infile [ outfile ]”
exit 1 # terminate script w. non-zero exit code
}
usage # call, no arguments this time
bash routines (i.e., functions) Example
• Routine arguments are accessed the same as in the script
$ cat scriptfile
#!/bin/bash
rtn() {
echo ${#} # number of command-line args
echo ${0} ${2} ${4} # some args
echo “${*}” # all args as a single string
echo “${@}” # all args as separate strings
echo ${$} # process id of executing sub-shell
return 17 # routine exit status
}
rtn a1 a2 a3 a4 a5 # invoke routine
echo ${?} # print routine exit status
exit 21 # script exit status
Example
$ ./scriptfile # run script
5 # number of arguments
scriptfile a2 a4 # script-name / args 2 & 4
a1 a2 a3 a4 a5 # args 1-5, 1 string
a1 a2 a3 a4 a5 # args 1-5, 5 strings
27028 # process id of sub-shell
17 # routine exit status
$ echo ${?} # print script exit status
21
End
CS246