Cover V03, I06
Article
Listing 1

nov94.tar


fcd: A Smart Change Directory

Fred Brunet

Command interfaces such as the UNIX shells give the user a lot of power and flexibility, but they are demanding. Along with command names and parameter syntax, users have to remember (and type) long and complicated directory paths. Most users of the Korn or C shell become very adept at using the history functions to save themselves keystrokes, but at best the history functions only let you avoid typing a long directory twice (you still have to type it correctly once). Some users create aliases and environment variables for certain directories, but if there are many directories, this method becomes unwieldy. I have written an extension to the Korn shell cd command, called fcd, that can free the user from ever typing a full path. fcd determines the full path when given a substring, then "cd's" to the full path.

fcd maintains a database of full paths to directories. When the user enters a path to fcd, fcd looks for that path as a substring in a longer path. If an exact match is found, fcd can go to that directory immediately. Unfortunately, the substring is usually ambiguous -- that is, it is contained in more than one full path. By default fcd minimizes ambiguities by assuming that the substring typed is the name of the deepest subdirectory of the corresponding full path. In this mode, if you type "fcd bin", a possible destination is /usr/bin, but not /usr/bin/backup. The deepest subdirectory in a path is the last part of the path, so all fcd has to do is look for a match at the end of a line (a trivial task for grep).

Where an ambiguity exists at the deepest subdirectory level, fcd resolves it by letting the user pick the full path from a list. For example, suppose your file system (and the fcd database) contains /usr/ed/apps/bin and /usr/bin. If you enter "fcd bin", fcd presents the following message:

1 : /usr/bin
2 : /usr/ed/apps/bin
Which of the above do you mean (enter number or 'q' for none)?

fcd uses a database of directory paths because it would take too long to search the file system each time it gets called. fcd in effect does the search ahead of time. Although this makes fcd work very quickly, the database may not reflect the actual state of the file system, especially if directories are added and deleted frequently. When it finds a discrepancy, fcd can update its database to make the correction.

fcd adds to its database in several ways. When it is first run, and no database exists, it creates one by scanning all the directories in the user's $HOME directory. Later, if the user types in a directory name that is not in the database, fcd prompts for the full path of the directory, which it then adds to the database. fcd also adds to the database when the -p and -r flags (discussed below) are used.

fcd deletes from its database in two situations. First, if the user chooses "q" to quit after getting a list of possible directories, fcd sorts and checks all lines in input, deleting any duplicates. Second, if fcd attempts to change to a directory that no longer exists, it deletes that line from the database.

Options

Several options make fcd more useful. These options are activated by single letter commands, preceded by the ("-") character. The -e option overrides the standard search method of fcd. It causes fcd to use extended search mode. Instead of searching at the end of each line, fcd searches the entire line. This is useful if the user wants to type in only the middle part of a long directory name, or to get a list of many directories under a certain directory. The drawback is that too many matches are usually found. For example, for "fcd -e bin" (using the same file system as in the previous example), fcd presents a list of /usr/bin, /usr/ed/apps/bin, and all the directories under those directories, plus any other directory that contains the string "bin" somewhere in the middle, including a name like /apps/binary.

The other two options log new directories. When you use these options, fcd does not process other arguments. The -p option logs the current directory. The -r option makes fcd recursively add the current directory and all its subdirectories. To add the entire file system to the fcd directory, a user could go to the root directory and type "fcd -r".

Installation/Setup

fcd is able to change directories because it runs in the current process. For this reason, it probably should not be a normal shell script. A shell script is run as a child process of your shell, and environment changes made in the child process (including the current directory) do not affect the parent. The dot (".") command allows you to run a shell script in the current process, but it is inconvenient for the user to type ". fcd directory". A better method is to make fcd a function. The first version of fcd was created on an NCR3000. The AT&T SVR4 UNIX running on the system allowed the use of the ksh autoload command to load fcd into the shell environment. Unfortunately, this does not work properly on our SCO UNIX, so fcd is now in the .kshrc file.

The .kshrc file should be loaded automatically by ksh when a new shell is spawned. If .kshrc is not automatically loaded on your system, you may need to set the ENV variable to $HOME/.kshrc in your .profile. If this still does not work, you should be able to run .kshrc by entering ". .kshrc" after logging in. Once fcd is loaded, no further setup is required. The database is created and updated through normal use. You only have to be careful not to delete the file fcd.list from your home directory.

The Program

The .kshrc file in Listing 1 includes the function fcd plus the necessary support functions. Code at the top of the file prevents fcd from being loaded into subshells. Without this code, many programs that spawn subshells would load fcd and display the fcd banner. For this reason, if you are already using .kshrc, the listing should come after any code you want executed for each subshell.

The first function in the file is addline. This is called when a directory must be added to the database by the user. Next is a usage function that is called when fcd is run without arguments. The last function is fcd itself. fcd starts by checking for special case parameters. One special case is the slash character (/). Since the slash character is in every full path, fcd assumes that the user who types "fcd /" wants to change to the root rather than get a list of every directory in the database. The rest of the special cases handle the options to fcd. Note that only -e does not exit immediately after processing; -p and -r ignore extra parameters.

After processing the special cases, fcd checks if the user's database file exists. If not, it creates one in the user's home directory using the find command. If you want the default database to have different contents you can change $HOME in the find command to something else. For example, if changed to "/", then the entire file system will be stored in the database. This is probably not necessary, since most users only visit a fraction of the directories on a system. find automatically skips directories that the user cannot access, so "bad" directories will not be added to the database.

Next fcd searches for the user's input using grep. If the user types the "-e" flag, the entire line is searched, otherwise just the end of the line is checked. The string is stored in a temporary file ($Duplist). The duplist file is counted to see how many matches are found. The best case is exactly one match, and the entire list is used for the match. If there are no matches, the user is informed, and invited to enter the full path of the directory to add to the database. If multiple lines (case *) are found, awk is used to print the list with numbers, and sed gets the line associated with the typed number. If the user doesn't want any of the listed directories, "q" exits the function without changing directories, but the database is sorted and duplicates are removed. Finally, if a match has been found, fcd prints the match on the screen and changes to that directory. If the cd command fails (the directory has been deleted or the permissions have been changed), fcd deletes the directory name from the user's database.

Conclusion

fcd could be improved in several ways. The biggest shortcoming is that the fcd database does not automatically reflect changes in the system's file structure. This is a difficult problem to solve because frequent scanning would cause the program to run very slowly. A useful improvement would be to allow interactive editing of the fcd database. The user can currently use vi to add or delete records from the database, but it would be better, especially for deletions, if the program had a friendly interface for this operation. Another useful feature would be to let the user control the order in which duplicate matches are displayed. Perhaps the most often used directories could filter to the top of the list. Finally, a graphic representation of the directory structure would be a major improvement. Most MS-DOS programs that work similarly to fcd show the directory as a tree, with levels that may be expanded and traversed using the cursor keys.

About the Author

Fred Brunet has a B.S. in computer science from California State University, Northridge and is currently a C and Informix programmer working on UNIX and MS-DOS platforms for jeTECH Data Systems in Moorpark, California.