Some Bash tips (HPR Show 1843)

Dave Morriss


Table of Contents

Introduction

If you are a command-line user (and personally, I think you should be prepared to use the command line since it's so powerful) it's likely that you have used the cd command to change directory.

There are other directory movement commands within Bash: pushd, popd and dirs. I'm going to describe these today.

Basic Usage

pushd dir

This command changes directory like cd but it does more, it saves the previous directory, and the directory you've moved to, in a stack.

So, assume you have logged in and are in your home directory:

dave@i7:~$ pwd
/home/dave
dave@i7:~$ pushd Documents
~/Documents ~
dave@i7:~/Documents$

pwd shows the directory I'm in. The pushd Documents takes me to my Documents directory. The stack is shown as a list, with the top of the stack on the left, and with ~ denoting the top-level home directory.

popd

This command moves back to the previous directory. To be more precise, it takes the top-most (current) directory off the stack and changes directory to the new top.

So, continuing with the previous example:

dave@i7:~/Documents$ popd
~
dave@i7:~$ pwd
/home/dave
dave@i7:~$

So, popd has moved me back to the previous directory.

dirs

This command displays the directory stack. By default the stack is shown as a left-to-right list as we have seen in the above examples.

Using the -v option to dirs shows the stack as a vertical list with index numbers:

dave@i7:~$ pushd Documents
~/Documents ~
dave@i7:~/Documents$ pushd subdir
~/Documents/subdir ~/Documents ~
dave@i7:~/Documents/subdir$ dirs -v
 0  ~/Documents/subdir
 1  ~/Documents
 2  ~
dave@i7:~/Documents/subdir$

Note that the directory stack is shown after each pushd but dir -v shows it vertically. The numbering begins with zero.

More advanced usage

The three commands we have looked have a lot more features than we've seen so far.

pushd

A slightly modified version of the pushd manpage is available at the bottom of this document.

You can use pushd to add a directory to the stack without changing to that directory. To do this use the -n option:

dave@i7:~$ pushd -n ~/Documents
~ ~/Documents
dave@i7:~$ pushd -n ~/Documents/subdir
~ ~/Documents/subdir ~/Documents
dave@i7:~$ dirs -v
 0  ~
 1  ~/Documents/subdir
 2  ~/Documents

Note that the order of the stack is not the same as it would have been if I had visited the directories in the same order.

You can manipulate the stack with pushd but the order is fixed, you can only rotate it (as if it's a loop) so that a particular directory is on top. This is done by using the option +n or -n (where n is an integer number not the letter 'n'). So pushd +2 means to rotate the stack so that entry number 2 counting from the left (or as numbered by dirs -v) is raised to the top. Everything else rotates appropriately:

dave@i7:~$ pushd +2
~/Documents ~ ~/Documents/subdir
dave@i7:~/Documents$ dirs -v
 0  ~/Documents
 1  ~
 2  ~/Documents/subdir

On the other hand pushd -0 rotates the stack but numbers the elements from the right (not the same as dirs -v):

dave@i7:~/Documents$ pushd -0
~/Documents/subdir ~/Documents ~
dave@i7:~/Documents/subdir$ dirs -p
~/Documents/subdir
~/Documents
~

Element 0 was the directory ~/Documents/subdir which is now at the top.

popd

A slightly modified version of the popd manpage is available at the bottom of this document.

As with pushd popd also takes a -n option which manipulates the stack without changing the current directory.

dave@i7:~$ pushd Documents/
~/Documents ~
dave@i7:~/Documents$ pushd subdir/
~/Documents/subdir ~/Documents ~
dave@i7:~/Documents/subdir$ popd -n
~/Documents/subdir ~
dave@i7:~/Documents/subdir$ popd
~
dave@i7:~$

Note that popd -n removed element 1 from the stack whereas plain popd removed the zeroth element.

As with pushd options of the form +n and -n are catered for (where n is an integer number not the letter 'n'). In this case popd +3 means to remove directory 3 from the stack, counting from the left, whereas popd -2 counts from the right.

This is not stack rotation as with pushd but deletion of elements. If the topmost element is deleted then the current directory changes:

# Traverse several directories
dave@i7:~$ pushd Test1
~/Test1 ~
dave@i7:~/Test1$ pushd Test2
~/Test1/Test2 ~/Test1 ~
dave@i7:~/Test1/Test2$ pushd Test3
~/Test1/Test2/Test3 ~/Test1/Test2 ~/Test1 ~
dave@i7:~/Test1/Test2/Test3$ pushd Test4
~/Test1/Test2/Test3/Test4 ~/Test1/Test2/Test3 ~/Test1/Test2 ~/Test1 ~
dave@i7:~/.../Test2/Test3/Test4$ dirs -v
 0  ~/Test1/Test2/Test3/Test4
 1  ~/Test1/Test2/Test3
 2  ~/Test1/Test2
 3  ~/Test1
 4  ~
# Now use popd +n to remove numbered directories
dave@i7:~/.../Test2/Test3/Test4$ popd +3
~/Test1/Test2/Test3/Test4 ~/Test1/Test2/Test3 ~/Test1/Test2 ~
dave@i7:~/.../Test2/Test3/Test4$ popd +0
~/Test1/Test2/Test3 ~/Test1/Test2 ~
dave@i7:~/Test1/Test2/Test3$ dirs -v
 0  ~/Test1/Test2/Test3
 1  ~/Test1/Test2
 2  ~
# Then use popd -n to count from the bottom of the stack
dave@i7:~/Test1/Test2/Test3$ popd -1
~/Test1/Test2/Test3 ~
dave@i7:~/Test1/Test2/Test3$ dirs -v
 0  ~/Test1/Test2/Test3
 1  ~

dirs

A slightly modified version of the dirs manpage is available below.

I have been using dirs -v to show the directory stack in what I think is a more readable form, but there are other options.

The -p option prints stack entries one per line without numbering. The -l option gives the full pathname without the tilde ('~') at the start denoting the home directory.

You can clear the entire directory stack using the -c option.

If you are thoroughly confused by the +n and -n options then using them with dirs makes it plainer what directories they refer to:

dave@i7:~$ cd; pushd Test1; pushd Test2; pushd Test3; pushd Test4
~/Test1 ~
~/Test1/Test2 ~/Test1 ~
~/Test1/Test2/Test3 ~/Test1/Test2 ~/Test1 ~
~/Test1/Test2/Test3/Test4 ~/Test1/Test2/Test3 ~/Test1/Test2 ~/Test1 ~

dave@i7:~/.../Test2/Test3/Test4$ dirs +3
~/Test1
dave@i7:~/.../Test2/Test3/Test4$ dirs -v
 0  ~/Test1/Test2/Test3/Test4
 1  ~/Test1/Test2/Test3
 2  ~/Test1/Test2
 3  ~/Test1
 4  ~
dave@i7:~/.../Test2/Test3/Test4$ dirs -3
~/Test1/Test2/Test3

Conclusion

What use are these commands?

I used to use them a lot pre-Linux when I was working on older Unix systems like Ultrix, SunOS and Solaris. This was in the days of real terminals and before the days of tabbed terminal emulators and virtual desktops.

I used to find it very helpful to be able to stop what I was doing in one directory and pushd to another to check something or answer a question, then popd back where I came from.

Nowadays I tend to have several terminal emulators on several virtual desktops and each has multiple tabs, so I use them to separate out my directories. However, if you tend to work in a single terminal session you might like I used to you might find them useful.


Manual Pages

pushd [-n] [+n] [-n]

pushd [-n] [dir]

Adds a directory to the top of the directory stack, or rotates the stack, making the new top of the stack the current working directory. With no arguments, exchanges the top two directories and returns 0, unless the directory stack is empty. Arguments, if supplied, have the following meanings:

-n    (a hyphen and the letter 'n')
Suppresses the normal change of directory when adding directories to the stack, so that only the stack is manipulated.
+n    (a plus and an integer)
Rotates the stack so that the nth directory (counting from the left of the list shown by the dirs command, starting with zero) is at the top.
-n    (a hyphen and an integer)
Rotates the stack so that the nth directory (counting from the right of the list shown by the dirs command, starting with zero) is at the top.
dir    (the name of a directory)
Adds the directory dir to the directory stack at the top, making it the new current working directory as if it had been supplied as the argument to the cd builtin.

If the pushd command is successful, a dirs command is performed as well. If the first form is used, pushd returns 0 unless the cd to dir fails. With the second form, pushd returns 0 unless the directory stack is empty, a non-existent directory stack element is specified, or the directory change to the specified new current directory fails.


popd [-n] [+n] [-n]

Removes entries from the directory stack. With no arguments, removes the top directory from the stack, and performs a cd to the new top directory. Arguments, if supplied, have the following meanings:

-n    (a hyphen and the letter 'n')
Suppresses the normal change of directory when removing directories from the stack, so that only the stack is manipulated.
+n    (a plus and an integer)
Removes the nth entry counting from the left of the list shown by dirs, starting with zero. For example: popd +0 removes the first directory, popd +1 the second.
-n    (a hyphen and an integer)
Removes the nth entry counting from the right of the list shown by dirs, starting with zero. For example: popd -0 removes the last directory, popd -1 the next to last.

If the popd command is successful, a dirs command is performed as well, and the return status is 0. popd returns false if an invalid option is encountered, the directory stack is empty, a non-existent directory stack entry is specified, or the directory change fails.


dirs [-clpv] [+n] [-n]

Without options, displays the list of currently remembered directories. The default display is on a single line with directory names separated by spaces. Directories are added to the list with the pushd command; the popd command removes entries from the list.

-c
Clears the directory stack by deleting all of the entries.
-l
Produces a listing using full pathnames; the default listing format uses a tilde to denote the home directory.
-p
Print the directory stack with one entry per line.
-v
Print the directory stack with one entry per line, prefixing each entry with its index in the stack.
+n    (a plus and an integer)
Displays the nth entry counting from the left of the list shown by dirs when invoked without options, starting with zero.
-n    (a hyphen and an integer)
Displays the nth entry counting from the right of the list shown by dirs when invoked without options, starting with zero.

The return value is 0 unless an invalid option is supplied or n indexes beyond the end of the directory stack.