Unix Scripting Dave Yearke Session 2 March 13, 2008
Tangent: Text Editors nano or pico – Really easy to use, not much power, but good for starting scripting. Emergency exit: Control-X vi – Preferred editor for Unix admins, powerful but learning curve involved. Emergency exit: Escape key followed by :q! emacs – Incredibly powerful, menu bar available in window mode, text mode can be challenging. Emergency exit: Control-X Control-C Other choices: gedit (X/GNOME), dtpad (X/CDE), vim/gvim (many including Windows)
Basic Shell Statements Variable assignment: name="george" count="5" today=`date` Variable unassignment: unset name Do basic math on a variable: counter=`expr $counter + 1` Read from standard input (usually console): read answer Print text: echo "Your name is $name"
Basic Shell Statements Conditional Execution: if .. elif .. else .. fi case word in pattern) .. ;; ... esac Loops and Iteration: for name in words; do .. done while list do; .. done
if … fi The “if” statement provides conditional execution of commands: count=5 if [ $count -eq 0 ]; then echo "Nothing left to do" fi name="Herbert" if [ "$name" != "George" ]; then echo "You're not George. I will name you George."
if … fi When doing text comparisons, always put variables inside double-quotes: name="" if [ $name != "George" ]; then echo "You're not George. I will name you George." fi “test: argument expected” is an error you may see a lot of at first. Because variable substitution happens early in the process, the above reduces to: if [ != "George" ]; then To be safe, put all variables in double quotes. It won’t hurt. Don’t use single quotes, variables aren’t expanded in them.
Test Test operators (located inside the square brackets) are described in the man page for “test”, not “sh”. Common String Test operators: Numeric String Equality $a –eq $b "$a" = "$b" Not Equal $a –ne $b "$a" != "$b" Greater Than $a –gt $b Less Than $a –lt $b Empty String -z "$a" Non-Empty String -n "$a"
Test Common File Test operators: Joining test operators: File Exists -f "$a" Directory Exists -d "$a" Symlink Exists -h "$a" File is Readable -r "$a" File is Writeable -w "$a" File is Executable -x "$a“ Negate any of the above ! –f "$a" Joining test operators: File Exists and is readable: if [ -f "$a" –a –r "$a" ]; then File is a file or a directory: if [ -f "$a" –o –d "$a" ]; then
if … elif … else … fi The “if” statement can provide alternative actions if the condition isn’t met: read response if [ "$response" = "yes" ]; then echo "We want to do that." elif [ "$response" = "no" ]; then echo "We don't want to do that." else echo "Huh?" fi
case … esac The “case” statement can evaluate alternate results for the same condition, and can also use file matching wildcard patterns: read response case "$response" in [Yy]*) echo "We want to do that." ;; [Nn]*) echo "We don't want to do that." ;; *) echo "Huh?" ;; esac
Getting Loopy The “for” loop: The “while” loop: for file in a b c d e; do echo "$file" done The “while” loop: done="no" while [ "$done" = "no" ]; do read magicword if [ "$magicword" = "plugh" ]; then done="yes" fi
I/O Redirection One of the most powerful features of Unix Three standard I/O channels: 0 – Standard Input (stdin) 1 – Standard Output (stdout) 2 – Standard Error Output (stderr) Redirect a file into a command using stdin: grep SENS < myreport Redirect command output into a file using stdout: ps –ef > processes Redirect input and output using stdin and stdout: grep SENS < infile > outfile
I/O Redirection Redirect stdout and stderr into the same file: grep SENS reports/* > out 2>&1 Redirect stdout and stderr into different files: grep SENS reports/* > out 2> badstuff Print to stderr instead of stdout: echo "It all went wrong!" 1>&2
Pipes Pipes take the output of one command and makes it the input of another command: Print just the year from the date command: date | awk -e '{print $6;}' date | cut –c 25-28 date "+%Y" Show how many processes are running: ps -e | wc -l Show how many processes I’m running: ps -ef | grep yearke | wc -l ps –fu yearke | wc –l The concept of the pipe is one of the fundamental underpinnings of Unix.
Semi-Practical Example 2.1 What side of the Node am I in? #!/bin/sh cd homedir=`pwd` case "$homedir" in /nsm/home/*) side="Natural Sciences and Math" ;; /eng/home/*) side="Engineering School" ;; *) side="Unknown" ;; esac if [ "$side" = "Unknown" ]; then echo "I'm sorry, I cannot determine your affilation." else echo "Your affiliation is the $side part of SENS." fi
Semi-Practical Example 2.2 Examine some files in the current directory: #!/bin/sh counter=0 for file in t*; do if [ -f "$file" -a -w "$file" ]; then counter=`expr $counter + 1` fi done echo "There are $counter writeable files starting with 't'."
Homework Write a script that runs on a Solaris 10 or Linux system (the unix.eng timeshares are great for this) and counts the number of files and directories under the “/etc” directory. You do not need to traverse subdirectories and enumerate files and directories under them, just the count under the top-level of “/etc” will be sufficient.
Links Current Solaris Bourne Shell man page: http://docs.sun.com/app/docs/doc/819-2239/sh-1?l=en&q=man+pages&a=view An Introduction to the Unix Shell: http://steve-parker.org/sh/bourne.shtml The Unix Programming Environment: http://www.amazon.com/Unix-Programming-Environment-Prentice-Hall-Software/dp/013937681X
Next Time Argument Clinic Child/Parent issues (environment) A lurking “gotcha” in loops