154 csh, pipes, and find Now suppose that “ftp” was a symbolic link (bear with me just a while longer). Suppose that it points to the directory /com/ftp/pub/ alan. Then after “cd ftp” I’m sitting in /com/ftp/pub/alan. Like all directories /com/ftp/pub/alan contains an entry named “. .” that refers to its superior: /com/ftp/pub. Suppose I want to go there next. I type: % cd .. Guess what? I’m back in /home/ar/alan! Somewhere in the shell (apparently we all use something called “tcsh” here at the AI Lab) somebody remembers that a link was chased to get me into /com/ftp/ pub/alan, and the cd command guesses that I would rather go back to the directory that contained the link. If I really wanted to visit /com/ ftp/pub, I should have typed “cd . / . .”. Shell Programming Shell programmers and the dinosaur cloners of Jurassic Park have much in common. They don’t have all the pieces they need, so they fill in the miss- ing pieces with random genomic material. Despite tremendous self-confi- dence and ability, they can’t always control their creations. Shell programs, goes the theory, have a big advantage over programs writ- ten in languages like C: shell programs are portable. That is, a program written in the shell “programming language” can run on many different fla- vors of Unix running on top of many different computer architectures, because the shell interprets its programs, rather than compiling them into machine code. What’s more, sh, the standard Unix shell, has been a central part of Unix since 1977 and, thus, we are likely to find it on any machine. Let’s put the theory to the test by writing a shell script to print the name and type of every file in the current directory using the file program: Date: Fri, 24 Apr 92 14:45:48 EDT From: Stephen Gildea gildea@expo.lcs.mit.edu Subject: Simple Shell Programming To: UNIX-HATERS
Shell Programming 155 Hello, class. Today we are going to learn to program in “sh.” The “sh” shell is a simple, versatile program, but we'll start with a basic example: Print the types of all the files in a directory. (I heard that remark in the back! Those of you who are a little famil- iar with the shell and bored with this can write “start an X11 client on a remote machine” for extra credit. In the mean time, shh!) While we're learning to sh, of course we also want the program we are writing to be robust, portable, and elegant. I assume you've all read the appropriate manual pages, so the following should be trivi- ally obvious: file * Very nice, isn’t it? A simple solution for a simple problem the * matches all the files in the directory. Well, not quite. Files beginning with a dot are assumed to be uninteresting, and * won’t match them. There probably aren’t any, but since we do want to be robust, we’ll use “ls” and pass a special flag: for file in `ls -A` do file $file done There: elegant, robust... Oh dear, the “ls” on some systems doesn’t take a “-A” flag. No problem, we'll pass -a instead and then weed out the . and .. files: for file in `ls -a` do if [ $file != . -a $file != .. ] then file $file fi done Not quite as elegant, but at least it’s robust and portable. What’s that? “ls -a” doesn’t work everywhere either? No problem, we'll use “ls -f” instead. It’s faster, anyway. I hope all this is obvious from reading the manual pages.