----------------------------------------------------- Chapter 11 Reading Guide - A Practical Guide to Linux ----------------------------------------------------- -IAN! idallen@ncf.ca Here is a Reading Guide and some review questions for a small part of Chapter 11 "Shell Programming". You will find questions similar to these on tests and exams. Chapter 11 - Shell Programming (excerpts) General Notes: Note: For much of the material, the Korn Shell (ksh), Bourne Shell (sh), and Bash Shell (bash) behave identically. C-Shells are different. Note: For practice, type in all the textbook scripts and command lines. You can't practice debugging the scripts simply by reading them. Practice writing them. Note: Concentrate on the text sections related to material covered in lectures, assignments, and in these questions. Don't read the whole book. Note: You must fix all the Linux text example shell scripts to conform to the rules for shell scripts. In particular, you should add the missing interpreter line ("#!/bin/sh -u") and set PATH and umask. Error messages should appear on Standard Error (1>&2), and should include the name of the script ($0) and what was typed ($# and $*). Note: Scripts should be run using "./scriptname"; because, you should never rely on "." being in your search PATH. Also, a script's name might match an existing Unix command name, and the Unix command might execute instead of your script. Skip over all the "Optional" sections in this chapter. We are concentrating on basic IF/ELSE and TEST this term. That means you can skip over the other sections of Chapter 11. - Studty IF/ELSE and the TEST command (p.369-373) - The text puts the "then" keyword of an "if" statement on a separate line. Many people prefer to put it on the same line as the "if": if test "$word1" = "$word2" ; then echo "$0: '$word1' matches '$word2'" else echo "$0: '$word1' does not match '$word2'" fi The semicolon is necessary to end the "test-command". (See the Linux text, bottom of p.373.) - True or False: The "test" command that often immediately follows the word "if" in an "if" statement is a shell built-in command in bash. (p.371) - What is the usual output (on STDOUT or your screen) of the "test" command? Try typing some test commands and see what you get on standard output, e.g. bash$ test a = b ...what prints here?... bash$ test 6 -lt 7 ...what prints here?... - True or False: The "test" command prints "1" or "0" on STDOUT depending on whether the test condition is FALSE or TRUE. (Try it!) - True or False: The "test-command" command that immediately followes the word "if" in an "if" statement must *always* be a shell built-in command. (See the example shell scripts posted under Notes.) - True or False: The "test-command" command in an "if" statement cannot be a pipe line or contain any redirection. (See the example shell scripts posted under Notes.) - Look under "Shell variables" in the index for the explanation of the "$#" and "$?" variables. What do these variables contain? - You should double-quote all shell variables to prevent shell glob characters from expanding. The $$, $#, and $? variables are exceptions - they don't really ever need to be quoted. Why? - What variable should a script first check to see if a user has supplied all the required arguments (positional parameters) to the script? (p.371) - What is the difference in return status (exit status) between the commands: $ test 0 = 00 $ test 0 -eq 00 $ test 1 = 01 $ test 1 -eq 01 What shell variable contains the exit status of the previous command? How can you see the contents of this (or any) shell variable on the screen? - What happens if you compare strings using -eq in the "test" command? $ test abc -eq def Don't do this. - Some versions of the "test" command don't like blanks around numbers. What is wrong with the following IF statement when used with bash V2? bash# echo "$BASH_VERSION" 2.04.0(1)-release bash$ x=" 123 " bash$ y=" 456 " bash$ if [ "$x" -lt "$y" ]; then echo TRUE ; fi [: 123 : integer expression expected Why is the test command complaining about the value in "$x"? Not all versions of the test command are this fussy about blanks; the ACADUNIX /bin/sh shell built-in TEST command removes the blanks. - What happens if you compare numbers using '=' in the "test" command? $ if test 100 = 0100 ; then echo TRUE ; fi - What happens if you give too many arguments to the "test" command? $ test abc def = ghi The above error can happen unintentionally: $ x='*' $ test "$x" = "*" ; echo $? $ test $x = "*" ; echo $? This is why you must remember to double-quote your variables! - What is wrong with this command line? (Students often write this!) if test $# > 1 ; then echo "$0: I found more than 1 argument" fi Hint: What command is the IF statement going to execute, and what arguments are being passed to that command name? Does it make sense? - Which of these commands tests to see if name $x is a directory? $ test -directory "$x" $ test "$x" -d $ test "$x" = "-d" $ test -d "$x" $ test "$x" = "d" $ test "d" -eq "$x" $ test -dir = "$x" How do you test to see if name $x is a file? How do you test to see if name $x is file with size bigger than zero? Are the quotes around $x necessary? - How do you test to see if string $str is not an empty string? (This is not the same as testing to see if a file is empty.) - What is wrong with this statement? (This is a frequent student error.) if -w "$x" ; then echo "$0: '$x' is writable" fi Hint: The IF must always be followed by Unix command line to execute. What command name is being executed in the "if" statement? - True or False: The command "test" and the command "[" have identical functionality. They are different names for the same thing. - Note the syntax difference between these two identical-in-function versions of the "test" command: if test A = B ; then ... fi if [ A = B ]; then ... fi The behaviour of the above commands is identical; the second one just looks a bit neater because of the brackets. (If you use the bracket form, you must have the closing bracket. If you use the command-name "test" form, you must NOT have any brackets.) REMEMBER: The brackets need to be seen as individual, separate arguments. Use blanks around them to make them into separate tokens. "if testA = B" is as wrong as "if [A = B]". <== WRONG WRONG WRONG Neither one works because of the missing blanks. (There are no Unix commands with names "testA" or "[A". A valid Unix command name must always follow the "if" keyword.) (Why don't you need blanks around semicolons and pipes?) - What is the output of these command lines? $ if [ -f /etc/passwd ] ; then echo hello ; fi $ if test -f /etc/passwd ; then echo hello ; fi $ if [ -d .. ] ; then echo hello ; fi $ if test -d .. ; then echo hello ; fi $ if [ -d /etc/passwd ] ; then echo hello ; fi $ if test -d /etc/passwd ; then echo hello ; fi $ if [ -f .. ] ; then echo hello ; fi $ if test -f .. ; then echo hello ; fi - What is wrong with this command line? (Students often write this!) if [ grep foo /etc/passwd ] ; then echo "$0: I found 'foo' in /etc/passwd" fi Hint: What command is the IF statement going to execute, and what arguments are being passed to that command name? Does it make sense? - What is wrong with this command line? (Students often write this!) if $# > 1 ; then ... - To keep the scripts short, example scripts in the text leave out code that verifies arguments. You must not forget this verification code in your own scripts. Validate user input before using it! - Chapter 11 Chapter Review questions: 1,2,6,9a,9b Important supplementary files (under Notes): showtest.sh.txt - sample TEST command lines iftest*.sh.txt - sample IF scripts Options to know for the "test" command: The six numeric compares: -le -lt -ge -gt -eq -ne The two string compares: = != Three permissions: -r -w -x Three file type: -e -f -d One file and one string size: -s -z