Unix Scripting Session 4 March 27, 2008
Answers to the Last Homework Print arguments in reverse order: #!/bin/sh output="" while [ $# -ne 0 ]; do output="$1 $output" shift done echo "$output"
Answers to the Last Homework Manage arguments in sets of three: #!/bin/sh if [ $# -eq 0 ]; then echo "Usage: $0 [arg [+-] arg] ..." 1>&2 exit 1 fi while [ $# -ne 0 ]; do tuple="" error="none" for arg in one two three; do if [ "$arg" = "one" ]; then tuple="$1" else tuple="$tuple $1" if [ "$arg" = "two" ]; then case "$1" in "+") ;; "-") ;; *) error="unknown operator $1 in" ;; esac [0-9]*) ;; *) error="$1 is not a number in" ;; shift echo "Error: Missing argument in $tuple" 1>&2 done if [ "$error" != "none" ]; then echo "Error: $error $tuple" 1>&2 echo "$tuple"
Answers to the Last Homework Count the words in “space_tff”, version one with an unexpected bug: #!/bin/sh linecount=0 wordcount=0 cat /eng/home/yearke/scripting/space_tff | \ while read line; do linecount=`expr $linecount + 1` for word in $line; do wordcount=`expr $wordcount + 1` done echo "The file has $linecount lines and $wordcount words."
Answers to the Last Homework Count the words in “space_tff”, version two with more accurate use of a child process: #!/bin/sh linecount=0 wordcount=0 cat /eng/home/yearke/scripting/space_tff | \ (while read line; do linecount=`expr $linecount + 1` for word in $line; do wordcount=`expr $wordcount + 1` done echo "The file has $linecount lines and $wordcount words.")
Answers to the Last Homework Count the words in “space_tff”, version three using the IFS environment variable: #!/bin/sh linecount=0 wordcount=0 ORIGIFS="$IFS" IFS=" " for line in `cat /eng/home/yearke/scripting/space_tff`; do linecount=`expr $linecount + 1` LINEIFS="$IFS" IFS="$ORIGIFS" for word in $line; do wordcount=`expr $wordcount + 1` done IFS="$LINEIFS" echo "The file has $linecount lines and $wordcount words."
Answers to the Last Homework Print “space_tff” with the lines reversed: #!/bin/sh cat space_tff | \ while read line; do newline="" for word in $line; do newline="$word $newline" done echo "$newline"
Job Control Processes that are attached to your terminal session are said to be running in the “foreground”. Processes that are unattached from your terminal are running in the “background”. To run a job in the background, simply put an ampersand (“&”) at the end off the line: ./takesalongtime &
Job Control The “wait” command tells the parent process to wait for the child to finish: #!/bin/sh ./childjob & # Do some other stuff wait # Do some stuff with the child's results echo "All done. Bye bye!" A background task will stop if you log off. To avoid this, “nohup” it and redirect all output: nohup ./childjob > results 2>&1 &
Using Exit Status With “if” The exit status of a command can be used directly with the “if” statement: if grep Space space_tff; then echo "Found it!" else echo "Didn't find it." fi Sometimes you want to hide the actual program output to avoid cluttering your script’s output: if grep Space space_tff > /dev/null 2>&1; then The “/dev/null” file is the system bit-bucket. Anything redirected to it is thrown away.
Conditional Process Execution (the “Short Circuit” operators) Recall that “;” allows multiple commands per line. “&&” and “||” do the same thing, but the following command or commands are only executed if the previous command succeeded or failed, respectively: grep Space space_tff && echo "Found Space." grep Kirk space_tff || echo "Didn't find Kirk." Or, hiding any program output: grep Space space_tff > /dev/null 2>&1 && echo "Found Space." grep Kirk space_tff > /dev/null 2>&1 || echo "Didn't find Kirk.“ Fun fact: These have the opposite meaning in some older versions of C-Shell, but this is mostly fixed now. Be careful, though.
Twelve Useful Unix Commands Reference: http://www.eng.buffalo.edu/~yearke/unix/commands12.shtml man ls cat tail (and head) grep (and egrep and fgrep) Sort wc diff (and cmp) find sed awk cut
“man” and “ls” Mostly used interactively, not in scripts. In fact I can’t think of why you would use “man” in a script, but it’s too important to ignore. “ls” is mostly interactive but does have some scripting uses. As you become more familiar with “find”, though, you may tend to not use “ls” as much in scripts.
“cat”, “tail”, and “head” cat is most useful for feeding a file through standard output to another process, or for concatenating (hence the name) a bunch of files together into stdout: tail shows (by default) the last 10 lines of a file, and head (by default) the first 10 lines. These can be useful when you want to process part of a very large file, such as a system log.
The “grep” Clan grep is the “Group Regular Expression Parser”. It finds text strings in files or streams. There are a lot of metacharacters and arguments that can be used to fine-tune the search parameters. egrep (Enhanced grep) adds additional metacharacter capabilities which can provide even better pattern-matching. fgrep (Fixed grep) treats all metacharacters as literal characters, eliminating the need to escape them with backslash. “f” does not stand for fast!
“sort” and “wc” The sort command, obviously, sorts files. It takes a lot of arguments that can be used to tune the sort fields and how they’re treated. Filtering out repeated lines and treating fields as numbers are particularly useful. The word counter, wc, also counts lines and characters. I tend to use the line counting feature a lot when I want to determine if a command returned meaningful output, or not.
Exercises None this time.
Links Twelve useful Unix commands (for next time): As usual, the current Solaris Bourne Shell man page: http://docs.sun.com/app/docs/doc/819-2239/sh-1?l=en&q=man+pages&a=view Twelve useful Unix commands (for next time): http://www.eng.buffalo.edu/~yearke/unix/commands12.shtml (This is part of a work-in-progress and might be a little rough, I haven’t looked at it in a while but will do so this week.)
Next Time Twelve useful Unix commands for scripts, part 2: diff (and cmp) find sed awk cut Regular expressions.