Bash Shell Change Directory Script

Fri Nov 20 2015  [Updated: Wed Jan 10 2018]

If you are a *nix user and work from the command line primarily, you often use the ‘cd’ command to move from directory to directory during the course of your work. Some of the directory paths can get long when you are trying to keep things organized in a meaningful way. When you realize you have to go back to /usr/lib/product/setup/appearance/xml for the 10th time, you might wish you didn’t have to type out that long path each time. What you need is to keep a history of the directories you’ve been in and some shortcuts for getting back to them. Well, that’s the purpose of the sd.bash shell script. This script should work on any operating system as long as you are using the bash shell.

You can download sd.bash at Bitbucket.org. If you want to try it out, download the file and put it in a directory, say $HOME/bin, and then set an alias to source it:

alias sd="source $HOME/bin/sd.bash"

If you decide to use sd.bash on a regular basis, you’ll want to set this up in your .bashrc file and we’ll show you how to do that later in this article.

Now that you have the alias set up, enter the command “sd -h” to display the help information for this utility. You should get the following output:

Usage:
sd        ==> display current directory
sd dir    ==> goto directory "dir"
sd ~      ==> goto home directory
sd %      ==> goto home directory
sd ..     ==> go up one directory level
sd ...[s] ==> goto subdirectory containing string s
sd -      ==> go back to previous directory
sd -[n]   ==> change to saved directory number n
sd =[n]   ==> display saved directory number n
sd -h     ==> display this help message
sd -i [s] ==> display and select from saved directories
              (optional: only those containing string s)
sd -l [s] ==> display list of saved directories
              (optional: only those containing string s)
sd -p     ==> go back to previous directory
sd -s     ==> explicitly save current directory
sd -t     ==> display all subdirectories (tree)
sd -x     ==> goto explicitly saved directory (see sd -s)
sd -S     ==> save history to ~/.sd_histfile
sd -L     ==> load history from ~/.sd_histfile
sd -C     ==> clear out directory history from memory
sd -CC    ==> remove directory history file

Now you can use the command ‘sd’ in place of ‘cd’ to change directories and as the help output states, it will remember the 20 most recent unique directories you visit. You can change the number of directories it remembers by setting an environment variable. To set it to 30 directories:

SDHISTSIZE=30

Once you’re confident that the ‘sd’ command works reliably, you’ll probably want to alias ‘cd’ so it runs sd.bash instead of calling the built-in ‘cd’ function:

alias cd=sd

As a historical note, sd.bash is based on a DCL command procedure I wrote for the OpenVMS operating system years ago. The command to change directories on OpenVMS is ‘SET DEFAULT’, so I used ‘sd’ as a shortcut for this command. In addition, on OpenVMS the equivalent to ‘pwd’ for showing your current directory is the command ‘SHOW DEFAULT’. So the ‘sd’ command also handled this function if you used it without any arguments. I have maintained this behavior in sd.bash, so using the command ‘sd’ with no arguments shows your current working directory just like ‘pwd’. In addition, sd.bash by default will print the new working directory after successfully changing directories. These are the two instances where, given the same arguments, the behavior of sd.bash differs from ‘cd’. If you want sd.bash to act just like ‘cd’, you can use these two environment variables:

SDDEFARG=$HOME
SDSILENT=1     

The first environment variable tells ‘sd’ that if it is executed without any arguments, act like it did get an argument of $HOME. In other words, ‘sd’ alone will result in ‘sd $HOME’ taking you back to your home directory which is what ‘cd’ alone would do. Setting ‘SDSILENT=1’ tells ‘sd’ not to print out the directory after each change.

Usage Examples

Time to look at some examples of using ‘sd’. Let’s try changing directories a few times.

$ sd /etc
/etc
$ sd /usr/lib
/usr/lib
$ sd xorg
/usr/lib/xorg
$ sd ~
/home/barton

Aside from printing out the new directory after each change, this is the same as using ‘cd’. However, ‘sd’ has saved all the directories we visited as we can see if we give it the ‘-l’ (list) option:

$ sd -l
p = /usr/lib/xorg (previous)
0 = /home/barton
1 = /etc
2 = /usr/lib
3 = /usr/lib/xorg  

Say we need to get back to the /usr/lib/xorg directory again. We have a number of options. Explicitly typing in the full path again:

$ sd /usr/lib/xorg
/usr/lib/xorg  

Enter part of the path and let us choose from any saved directories that contain a match:

$ sd -i xorg
3 = /usr/lib/xorg

Enter a directory number: 3
/usr/lib/xorg

If we remember the memory location of the directory we want from doing a previous ‘sd -i’ or ‘sd -l’ command, we can just use that number directly:

$ sd -3
/usr/lib/xorg

A variant on this direct memory slot addressing is to use the “=n” option to print out the directory path. For example, we could list the contents of /usr/lib/xorg by using the command:

$ ls `sd =3`  

You can search for a subdirectory using the ‘…’ argument. So the command ‘sd …xx’ will look for a subdirectory under the current directory containing the string ‘xx’. It will go to that directory immediately if there is a single match, or let you choose from a list if there are multiple matches.

The sd command processes each argument separately and sequentially, so ‘sd arg1 arg2’ is equivalent to entering two separate commands ‘sd arg1’ and then ‘sd arg2’. Let’s combine this behavior with the ‘…’ argument to show yet another way of getting to /usr/lib/xorg:

$ sd /usr ...xorg  

Of course this example is not saving us any typing, but is handy if you want to get to subdirectory ‘b’ that you know is somewhere (perhaps many levels) below directory ‘a’. You would use the command ‘sd a …b’ or just ‘sd …b’ if you are already in directory a.

If there is a directory you know you will be returning to, you can explicitly save it with the command ‘sd -s’ to save the current directory. Now you can return to that directory with the command ‘sd -x’.

To return to your previous directory, use the command ‘sd -‘ or ‘sd -p’.

All the options that search for strings (i.e. the ‘-l’, ‘-i’, and ‘…’ options) accept regular expressions. While the string ‘xorg’ would match the paths “abc/xorg” or “abc/xxxorgan”, using the command:

$ sd -i '/xorg$'  

would ensure only paths ending in a directory named ‘xorg’ will match. Note that I had to use single quotes so the shell won’t try to expand the dollar sign.

.bashrc Setup

You’ll want to configure sd in your .bashrc file. This will make use of some additional sd options that deal with the history file so we can retain all our saved directories between login sessions. Here’s how I set up sd in my .bashrc file:

if [ -f $HOME/bin/sd.bash ]
then
    alias sd="source $HOME/bin/sd.bash"
    alias cd=sd
    SDAUTOSEARCH=1  # enable autosearch mode
fi
# Define a function to perform commands when the shell exits
shell_exit() {
    sd -S   # save our sd history
}
trap shell_exit EXIT # set it to execute on exit  

Lines 1-6 set up the aliases and any variables to modify the sd.bash default behavior. I have it inside an ‘if’ block to make sure the sd.bash file is installed on this computer so I don’t break my ‘cd’ command. The only variable I’m setting is SDAUTOSEARCH. By setting that to 1, if I give sd an argument that is not a valid directory, then it will automatically check if it is a partial match to any of the saved directories. So in other words, you no longer need to use the -i option.

If we want all our remembered directories to be available to us the next time we log in, we have to save them in a file. Lines 8-10 above define a function that executes the ‘sd -S’ command to save our directory history to a file. Line 11 tells the bash shell to execute that function when we log out.

Use the ‘sd -h’ command to list all the options available to you and play with each one to get a feel for how they work. Hopefully you’ll find this to be a useful script.

Keywords: bash,script,linux