CS/CE218 --- Unix and C Programming. 30 September 91 Name: TA: Section: HOMEWORK 3: SHELL PROGRAMMING Due: 14 October 1991 Be sure to work this homework on Zippy or Zaphod, since there are small differences between HP-UX and other versions of Unix (e.g., on Vincent) that will cause you to get different answers on other systems. For each of the shell scripts (shell procedures), include the contents of your file in the printout that you hand in for this homework, and also leave an executable copy in your directory $HOME/bin. That is, create a subdirectory in your home directory (mkdir $HOME/bin) and make sure it is readable by the course staff (chmod +rx $HOME/bin). (Your home directory should be owned by group cs218s and mode 750; this is the way the directory was created, so you shouldn't have to do anything to make that happen.) 1. (5 pts) Write a shell script ``phone-decode'' that takes a phone number such as ``1-800-eat-meat'' and translates it into just numbers. For example, $ phone-decode 1-800-VEG-ONLY 1-800-834-6659 The translation is as found on a touch-tone phone, given by the following: letters | translated number a,b,c 2 d,e,f 3 g,h,i 4 j,k,l 5 m,n,o 6 p,r,s 7 t,u,v 8 w,x,y 9 Your translation should work with both lower and upper case characters. It should pass nonalphabetic characters through unaltered, but should give an error message (on the diagnostic output) if the argument contains one of the characters: q, Q, z, or Z. 2. (10 pts) Write a shell script ``filter-phone-decode'' that acts as phone-decode of problem 1 when given a command line argument, but if no argument is given, it reads phone numbers from standard input, and prints their translations on standard output. This command should prompt to the terminal (/dev/tty) if its standard input is coming from a terminal (use test -t 0). Otherwise the script should not prompt. For example, $ filter-phone-decode 1-800-VEG-ONLY 1-800-834-6659 $ filter-phone-decode >junk number? eat-meat ^D $ cat junk 328-6328 $ echo eat-meat | filter-phone-decode 328-6328 $ echo $? 0 3. (5 pts) Write a shell script ``exit-value'' that takes a Unix command as an argument (similar to arguments to ``nohup'' and ``nice''), runs that command, prints on the diagnostic output (standard error) the exit value of that command, and then exits with that command's exit value. For example, consider the following (with the Bourne shell) $ exit-value false 1 $ exit-value echo hi there 2>junk hi there $ echo $? $ 0 $ cat junk 0 $ exit-value grep -x foo grep: illegal option -- x usage: grep [ -bcilnvs ] [[ -e ] expression ] [ -f file ] [ file ] ... 2 $ echo $? 2 4. (15 pts) Write a shell script ``cleanup'' that optionally takes a directory name as an argument (default .), and for each file in the directory that is *not* - a c file (i.e., a file matching *.c) or - a file named ``Makefile'' or ``makefile'' asks the user if the file should be deleted. If no argument is given, the script should cleanup the current working directory. If the standard input of the command is not a terminal, the command should give an error message. If more than one directory name is given as an argument, or if the directory is not writeable, or if any other error situation occurs, the program should print a suitable error message to the diagnostic output, and exit with a non-zero exit value. This command should not attempt to remove subdirectories of the given directory For example, $ ls Makefile bar foo junk junk.c my-directory $ cleanup bar: ? (y/n) n foo: ? (y/n) y junk: ? (y/n) y $ echo $? 0 $ ls Makefile bar junk.c my-directory $ cleanup . bar: ? (y/n) n $ ls Makefile bar junk.c my-directory $ echo y | cleanup cleanup: ERROR: standard input is not a terminal. $ echo $? 1 $ chmod -w . $ cleanup cleanup: ERROR: directory `.' is not writeable $ echo $? 2 $ cleanup /home / /tmp Usage: cleanup [directory] $ echo $? 1 5. (20 pts) Write a shell script ``numeral-trans'' that translates numerals from 1 to 26 into different numeral systems. There are 4 numeral systems that the command should understand, each controlled by a different option: -r lower case roman numerals (i, ii, iii, iv, v, vi, vii, viii, ix,...) -R upper case roman numerals (I, II, III, IV, ...) -a lower case alphabetic (1=>a, 2=>b, etc.) -A upper case alphabetic (1=>A, 2=>B, etc.) For example: $ numeral-trans -r 3 iii $ numeral-trans -R 4 26 IV XXVI $ echo 7 8 9 | numeral-trans -a g h i $ echo '1\n2\n3' | numeral-trans -A A B C $ numeral-trans 3 Usage: numeral-trans -r [number ...] numeral-trans -R [number ...] numeral-trans -a [number ...] numeral-trans -A [number ...] $ numeral-trans -a 27 numeral-trans: ERROR: 27 is too large $ Your script should follow all the standard Unix conventions with regard to error messages and exit codes. For this problem you must also use shell functions. For example, as part of your script you might use the following function lower_case_roman() { #... } Part of your score will depend on how wisely use use shell functions. 6. (extra credit only) Make a copy of the the script $PUB/hw3/note and place it in your file $HOME/bin/note. This script knows how to deal with the lecture note files used by Prof. Leavens. Your task is to modify your copy of this script, so that whenever possible it produces a more standard outline. For example: $ $HOME/bin/note outline $PUB/hw3/basics.txt I. basics of the Bourne Shell A. Shell scripts (section 13.2) 1. executing shell scripts 2. shell variables (section 13.3) a. shell environment (predefined variables) (page 459) i. exported vs. non-exported variables ii. linkage (PATH) b. arguments (section 13.4) B. substitutions 1. command substitution (`cmd`) page 460 ... 7. (extra credit only) The command ``sed'' does not give the proper exit code when it is given an unreadable file as an argument. Write a shell script that calls /bin/sed to do the real work, but has the following behavior: $ sed -e 's/x/y/' foo Can't open foo $ echo $? 2 $ /bin/sed -e 's/x/y/' foo Can't open foo $ echo $? 0 (Hint, which you might not need to use: What exit value do you get from ``cat foo'' if ``foo'' doesn't exist? What exit value does a pipeline give in terms of the exit values of the sub-commands in the pipeline?)