Extending the bash 'cd' command in Linux

Tux logo In Linux shells, the cd command is generally built into the shell. We can add a new cd program, and even arrange for it to be executed, but it probably won't have any effect. The problem is that, although a new cd utility can change its own current working directory, it's not clear how it can change the working directory of the shell that launched it. Some Unix variants to provide a way to do this. To be honest, I'm not sure if it's just difficult in Linux, or actually unsupported.

In any case, if you want to make cd more smart, you'll probably have to look for a way to extend the functionality of the built-in cd. And cd certainly could be smarter. Here are a few things that cd might do, but doesn't:

The problem

There are various ways to extend the cd command, as a simple web search will reveal. However, many of them use peculiar or old-fashioned methods. With modern versions of bash, and perhaps other shells, extending built-in commands is easy. It is, however, not very well documented.

The solution

Implement your new cd command so that it takes its argument from the command line in the usual way, and outputs the new directory to standard out. It doesn't matter how this directory is arrived at -- from the command-line arguments, of from some list or algorithm -- but it should be written to standard out, followed by a line break.

Suppose this utility is called my_cd, for the sake of discussion.

Now execute the following shell script in the current shell session. By "in the current session" I mean that the script needs to be executed using source or . -- if it's run as a separate script, it will only affect that script's environment, which will be transient.

cd()
  {
  CD=`my cd "$@"`
  builtin cd "$CD"
  }

What this script does is to replace the built-in cd with the two lines of code in the function. The first invokes my_cd with the same command line as was passed to cd. It then stores the program's output -- which will be a directory name -- in the environment variable CD. The second line of code invokes the built-in cd, passing the contents of the CD variable as an argument.

The double-quotes in this example are important for controlling the way the shell works. In particular, if a directory name contains spaces, we want to avoid the name being split into separate arguments.

And that's all there is to it.

Gotchas

Well, almost...

The first thing to be aware of is that the my_cd utility -- whatever it does -- must write a directory name to standard out, even if it doesn't plan to change directory. The built-in cd will expect some input. If you don't want to change directory, just write "." as the directory name.

Second, be aware that my_cd can only write the directory name to standard out, and nothing else. If the program needs to interact with the user via the console, this needs careful handling. To write a simple, one-line error or informational message, it's probably safe to write it to standard error -- the script is only capturing standard out. For more sophisticated interaction, however, it's better to work directly with /dev/tty, and not use stdin/stdout/stderr at all.

Example

You can see a complete example of this technique in my qcd utility on GitHub.