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.
|