The Sun Observer, Volume 8 No.7
Peter V. Radatti
radatti@cyber.com
CyberSoft
July 10 1995
Notice: Copyright March 31, 1995 by Peter V. Radatti, All rights reserved.
Welcome back! This is the third edition in the series of this column. Remember to collect the entire set! Last month you learned how to use wild card operators, piping, command separators, the file, grep and more commands. This month you will learn how to use the find command. The find command is one of my favorites. It's useful for locating lost files, sorting files by many different options including age and acting as a front end filename generator for other commands. You may also remember that the all powerful Editor granted me an audience with President Clinton and Socks the cat. Let me tell you the dirty little secret I learned while in the White House! Did you know that Socks' paws are not really white! Yes! While I was there Socks accidentally stepped in the water bowl and the "sock" washed off! Shocking! The President tried to block my view pretending to show me a rare painting of President Washington but I saw the Secret Service painting the quote-unquote socks onto Socks! Can you say Sockgate? (Mister President, I know you read this column. Please don't get upset. Sockgate is just a joke! No hard feelings!)
Pretend that you lost the file which contains your Aunt's recipe for rubar- spinich-apple pie. You know the filename contains the word rubar but you just can't find it. There are thousands of files on the system and it can be anywhere. The easy way to find a file on a Unix system is to use the find command. Remember to find a file use the find command. The file command needs parameters to tell it what you want to do. Most of the command parameters are not position dependent except for the parameter just after the command itself. The parameter after a command is the first parameter since the command itself is considered parameter zero. The first parameter is always the starting point for the search. It specifies where the find command should start looking for the file you want to locate. If you know that the recipe has to be somewhere in the subdirectory menu then that would be what you specified as the second parameter. This parameter can be relative or absolute. Therefor selecting any option of "/users/pete/menu" is the same as selecting the option "menu" if your current working directory is already "/users/pete". You could also use a dot as a position parameter which means the current working directory. If I wanted to search all of the files in my home directory then I would change my path to the home directory then specify a dot as the second parameter to the find command. Next you need to tell the find command the name of the file you want to use. Since these commands are not position dependent you need to tell the command what option you are selecting. The filename you are searching for is selected using the "-name" parameter. Of course, it's not very often that you know the full filename that you are searching for. If you did, then you also know where it's stored and don't need to locate it. The "-name" parameter has provisions to solve this problem. You remember that the filename has the work "rubar" in it. You have already used wildcard operators and the good news is that the "- name" parameter allows wild card operators! When using wild card operators it is necessary to put the filename fragment with the operators in double-quotes. The full command at this point would appear as, [find menu -name "*rubar*]". Life is good! You can almost taste that rubar-spinich-apple now! If you pressed the enter command at this point the file command will execute and locate the file, but it wouldn't tell you. The find command is one of the exceptions to the rule of Unix commands being verbose. It won't say anything unless you tell it to! Too bad it doesn't work on Mother-in-laws! The parameter to tell file to tell you the answer is "-print". Our command now looks like [find menu -name "*rubar*" -print] and is good to go. Press enter and start the oven!
Having completed lunch, you return to the computer and wonder what other recipes are hidden in the menu directory. Again, the find command comes to the rescue. Don't specify a file name and the command will display all of the filenames. After executing [find menu -print |more] you notice that there are lots of directories in the structure. Since only files contain recipes you want to eliminate the directory names. The grep command won't help since the directory names don't indicate that they are directories! The file command might help but you have the problem in having to run the file command against all of the filenames to determine which ones are files and which directories. The find command provides another solution in the "-type" parameter. This parameter allows you to specify several types of files you can search for. While there are several options the only two we are going to use in this example are "f" which tells find to locate only plain files and "d" which tells find to locate only directories. If you executed the command [find menu -type f -print |more] you will very quickly compile a list of all the files under the menu subdirectory. Having completed this you notice that you arranged all of the files by food type. Each subdirectory of menu has names like "beef_dish", "pies", etc. To get a listing of only the directory's substitute the "f" option for "d". The command now reads [find menu -type d -print |more].
While locating files is very nice it's not the real power of the find command. The find command can execute command for you on each file located. Lets say you became a vegetarian and you now wanted to delete all files that contain the word meat. The "-exec" option allows you to execute the "rm" command as an option on all found files. You can also execute any other command. The command now looks like this, [ find menu -type f -name "*meat*" -exec rm {}\;]. The "{}" are metacharacters that tell the "rm" command to substitute the filename provided by the find command in that place. The "\;" terminates the command. Having purged yourself of all files whose filenames contain the word meat you want to know if there are any files which contain the word in the body of the file. Remember that so far we have only operated on filenames, not their content. The "grep" command can do this but executing "grep" by hand would take too long. Remember that the "-exec" option can execute any command , including "grep". Since you want to search all of the files in the menu subdirectory it's no longer necessary to use the "-name" parameter to limit the search. The command now appears as, [ find menu -exec grep meat {};\ |more]. This displayed lots of file contents that contained the word meat but didn't tell you the filename. One easy way to solve this problem is to write a new command of your own. One of the strong points of Unix is that you don't have to be a programmer to write new command. You can string commands you already know together in a file and execute the file. Files of this type are called "command files" or scripts. The filename of the script file is the name of the command. One of the features of script files is that they can read the command line itself. This makes it handy we want the find command to tell the script program a filename to search. The find command to do this is [find menu -exec myprogram {}\;] In this example I called our script program "myprogram". The first parameter passed to it is the filename to be examined. Remember that the command name itself is parameter zero therefor the first thing passed to the command on the command line is parameter one. You might think that the word "menu" is the first parameter but that is only true for the find command itself. The "-exec" option will execute the command specified and will therefor restarts the count.
Within script files you can reference items on the command line using the dollar sign followed by the number of the parameter. The reference "$1" refers to the first parameter, which in the case of our command will be the filename to be examined. Our object with this program is to display the name of the command under examination then search it for the word meat. We can make use of the "echo" and "grep" commands to accomplish this task. Since I normally like to use the csh shell I prefix my script files with a first line of "#/bin/csh -f". This tell the system to execute this script file using the csh command processor. There are also the Bourn and Korn command processors. We use an echo command to display a blank line to make the output easy to read followed by displaying the filename and the actual grep. The script program is displayed in figure 1.
---------------------------- #/bin/csh -f echo " " echo filename = $1 grep meat $1 -----------------------------
figure 1
When the find command is now executed it executes the myprogram command which displays each filename followed any contents that contain the word meat. In fact if you have lots of output you may wish to pipe the output into the more command. The command will look like [find menu -exec myprogram {}\; |more].
Next month we continue learning about scripts and I go to Hollywood where I get to use my Press Credentials to visit the stars. Maybe I can break into the movies! See you next month.
Pete Radatti is the founder and CEO of CyberSoft, Inc. CyberSoft manufactures, VFind the an antivirus software product that executes under Unix and simultaneously scans for Unix, MS-DOS, Macintosh and Amiga destructive software. You can reach Pete at radatti@cyber.com.





