Shell Scripting 2
Shell Scripting 2
Jeremy Portzer
[email protected]
Shells
●
sh = “Bourne Shell”
– Named after author, old Unix standby shell
●
csh = c-shell, C like syntax structures
– tcsh = modern somewhat updated version
●
ksh = Korn Shell
– Introduced job control and other popular features now in bash
●
bash = “Bourne Again Shell”
– Variant of ksh, Popularized by Linux
– By far most common shell used today
●
Perl/Python = interpreted programming languages with
many more features than shell, but can be used as
more advanced platform for same tasks as shell scripts
Shell Concepts
●
Basic script is equivalent of “Batch File” in DOS – list of
commands to be executed in order, but many better
features
●
Ideal for cross-platform, quick jobs, not overly complex
programs
●
Shell scripts commonly used in boot scripts and OS-
related automation tasks
● Not ideal for complex data strutures or variable types,
random file I/O, or many other things found in full
programming languages. Perl is a good alternative.
●
Shell scripts rely heavily on external utilities and tools
present in the OS. Compatibility can be a big issue.
Hello, World
●
Basic script:
#!/bin/bash
●
Note blank line after shebang.
●
Give permission mode +x, such as 755, to be run from
command line (man chmod for explanation of modes)
●
Recommend personal scripts be stored in ~/bin,
system-wide in /usr/local/bin
●
Edit PATH setting in ~/.bashrc if needed
●
Shell scripts cannot be setuid in Linux. Use sudo.
First things first: Standard files
●
Standard Output
– Output of a shell command, e.g. default location of echo or print
statements. Can be redirected to a file with > operator, which
overwrites its destination
– echo “Hello, World!”
echo “Hello, World!” > file.txt
cat file.txt > file2.txt
>> operator appends instead of overwrites
● Standard Input
– Where many commands get their data from.
●
If not provided, bash reads stdin from the terminal
– One line processed at a time
– use ^D on a line by itself to indicate end of file.
●
cat > file3.txt
●
Redirect with < operator, e.g. cat < file2.txt
●
What does the “cat” command when run alone? Why?
Standard files, con't
●
Standard Error
– Similar to standard ouptut, but used for error messages. This
way, if standard output is re-directed, the error message is still
seen (or at least it goes somewhere else)
– Redirect with 2>; note difference in these commands:
●
cat /no/file/here > file3.txt
●
cat /no/file/here 2>/dev/null
– Print to standard error with >&2
●
echo “An error has occurred! Blame jtate!” >&2
●
Other file descriptors
– There is a system for using other file descriptors above 2, for
your own purposes. I have no clue how it works, but I needed
to put something in this space.
Pipelines
●
A pipe redirects standard output of one command to the
standard input of the next one
●
Explain these pipelines
– tac /var/log/messages | less (or “more”)
– who | grep jeremy
– cat /var/log/messages | tail
●
Can include multiple commands, various input/output
redirections, etc.
– uniq < file.txt | sort | uniq
– sort -n -k 3 -t : < /etc/passwd | cut -f 1 -d : | xargs echo
●
“Filters” are commands that take stdin, do something
with it, and output the data on stdout.
●
Can span multiple lines for readability
Super-Simple Scripts
●
Many scripts simply run a few commands that you would
want to do frequently. For example:
#!/bin/sh
●
Note, sh is a symlink to bash and invokes a supposedly
[Bourne] sh-portable environment
●
Run this from cron every N hours (real motd in
/etc/motd.in):
cat /etc/motd.in > /etc/motd
/usr/games/fortune -s >> /etc/motd
Variables
●
Variables are essentially always strings, traditionally
named in all caps, expanded with $ or ${}, and are set
without $ at the start of a line:
SPAM=$HOME/mail/spam
mv $TENSPAM ${SPAM}.tmp
sa-learn --showdots --spam --mbox $SPAM.tmp
rm ${SPAM}.tmp
●
Export command makes available to sub-programs, ie,
"export SPAM=..." to set and export, or "export SPAM"
to just export. Needed in ~/.bashrc, e.g. with PATH
●
"set" and "env" commands list environment variables
currently set; some already set like UID, HOME.
●
Variables expanded within double-quotes, but not within
single quoted strings (compare echo “$HOME” with echo '$HOME')
Commands and Operators
●
Many built-in commands available. “man bash”
contains complete list. “help <command>” gives usage
info for each command, or just “help” to list built-ins.
●
Some commands exist as both built-in and separate
binaries, i.e.: true, test, time (use “type” command)
●
There aren't really “operators” in bash, but the test
command, abbreviated as [, gives illusion
MHZ=$(grep "cpu MHz" /proc/cpuinfo | cut -d : -f2)
MHZINT=`awk -F. '{print $0}'`
if [ $MHZINT -lt 500 ]
then
echo “Your machine is slow. Blame jtate."
fi
●
$() and `` converts commands' standard out into args.
– grep :`id -g`: /etc/passwd
Exit Status
●
One "char" of information is passed between Unix
processes in the exit status field, which is used
extensively by the shell. Zero is "successful" or true,
nonzero is false, backwards from standard
programming
jeremy@jeremy ~ $ /bin/true
jeremy@jeremy ~ $ echo $?
0
jeremy@jeremy ~ $ /bin/false
jeremy@jeremy ~ $ echo $?
1
●
Control structures use command exit status to determine
flow.
● "exit" command, as in C, exits your script with given
status
Control Structures
●
if/then/elif/else/fi
if [ $UID != 0 ]
then
echo "you are not root"
logger -p security.alert "$USER is running $0 at `date`"
elif [$HOME != /root ]
then
echo 'home directory is wrong"
else
# do something
fi
●
while/do/done
while true
do
#something
done
Control Structures, con't
●
case/;;/esac -- demonstrated in "apt-yum" script :
case "$1" in
install)
shift
yum install "$@"
;;
update)
shift
yum list >/dev/null
yum clean oldheaders
;;
upgrade)
shift
yum update "$@"
;;
dist-upgrade)
shift
yum upgrade
;;
*)
echo "I don't know how to yummify that!"
exit 1
;;
esac
●
Note use of positional paremeters $1, $2, etc, shift, $@
for entire line
●
See getopt(1) for argument parsing "library"
Control Structures, con't
●
for/in/do/done
for i in foo*
do
mv $i ${i}.bak
done
●
For loop list whitespace separated (foreach in perl)
●
A C-like "for" is available but rarely used
●
Conditional control operators || and &&
– touch /etc/motd || echo "Error" >&2
– touch /etc/motd && echo "wrote to motd" >&2
●
Loops and branches can be nested as expected. Use
whitespace and CRs to make your scripts look sane
●
More complex arithmetic and conditionals are allowed,
but less used; see man bash, "let" command, "test"
command help, etc.
File I/O Goodies
●
Review - Dealing with standard error
– echo "error" 2>&1 # prints stdout on stderr
– touch /etc/motd 2>/dev/null #sends stderr to file
– ls /nowhere >/dev/null 2>&1 #sends stderr same place as
stdout, which in this case is /dev/null
●
Safe temporary files:
NAME=`basename $0`
TMPFILE=`mktmp /tmp/$NAME.XXXXXX`
if [ ! -w $TMPFILE ]
then
echo "Temporary File Creation Failed" >&2
exit 1
fi
# do stuff, using $TMPFILE variable
rm -f $TMPFILE
●
"Here" documents, multiple lines to stdin:
cat <<EOF
This is some
multi-line output.
EOF
Other I/O
●
"read" builtin to prompt user for variable (or to read one
line from an input file)
– Use with caution due to security implications
●
"logger" to send syslog messages
●
Send things to /bin/mail to output things to email
– Simple log analysis script example:
TODAY=`date "+%b %d"`
COUNT = $(
grep $TODAY /var/log/messages |
grep “authentication failure” |
wc -l
)
if [ $COUNT -gt 4 ]
then
echo -e “There have been $COUNT authentication failures
today. \nPlease investigate.” |
/bin/mail -s “Security Alert from `hostname`” jeremy@