By drupalmaster |
bash clipart

What is a stack and why is it important in Linux or Computer Science, for that matter? A stack, in the context of this article, refers to a last-in-first-out (LIFO) list or more affectionately referred to as a pushdown store. This is in contrast to another arrangement called first-in-first-out (FIFO) used in granaries since the grain is loaded at the top of the tower and dispensed at the bottom into trucks or other vehicles for delivery to its destination. In both cases, LIFO and FIFO can also be viewed as an array structure in which the elements of the array are loaded and emptied in some particular order. For example, the LIFO stack might be viewed as a PEZ dispenser which is loaded with candies from the top-down, then retrieved from the top of the dispenser, thus the last candy loaded is the first candy removed.  

The directory stack has a prominent place in the early development of Computer Science. Michael Mahoney, a pioneer in the history of the theory of computing between 1955 and 1970, stated “… a new agenda developed around the theory of automata and formal languages, which increasingly came to be viewed as foundational for the field as a whole….” We will be looking at the Bash directory stack in this article which follows the LIFO array structure in the terminal.

Directory Stack Builtins

For the purposes of this article before we dive into the concept of the Bash directory stack, we need to define some of the builtins in the Bash (Borne-Again Shell) in the Linux terminal that will be applied when we study Bash directory stacks. Let’s look at these one at a time:  

dirs

dirs [-clpv] [+N | -N] 

Display the list of currently remembered directories. Directories are added to the list with the pushd command; the popd command removes directories from the list. The current directory is always the first directory in the stack.   

–c

Clears the directory stack by deleting all of the elements.

–l

Produces a listing using full pathnames; the default listing format uses a tilde to denote the home directory.

–p

Causes dirs to print the directory stack with one entry per line.

–v

Causes dirs to print the directory stack with one entry per line, prefixing each entry with its index in the stack.

+N

Displays the Nth directory (counting from the left of the list printed by dirs when invoked without options OR counting from the top down in the list printed by 
dirs -v), starting with zero.

–N

Displays the Nth directory (counting from the right of the list printed by dirs when invoked without options OR counting from the bottom up in the list printed by 
dirs -v), starting with zero.

popd  

popd [-n] [+N | -N] 

When no arguments are given, popd removes the top directory from the stack and performs a cd to the new top directory. The elements are numbered from 0 starting at the first directory listed with dirs; that is, popd is equivalent to popd +0.

–n

Suppresses the normal change of directory when removing directories from the stack, so that only the stack is manipulated.

+N

Removes the Nth directory (counting from the left of the list printed by dirs OR counting from the top down of the list printed by dirs -v), starting with zero.

–N

Removes the Nth directory (counting from the right of the list printed by dirs OR counting from the bottom up of the list printed by dirs -v), starting with zero.

pushd

pushd [-n] [+N | -N | dir]

Save the current directory on the top of the directory stack and then cd to dir. With no arguments, pushd exchanges the top two directories and makes the new top the current directory.

–n

Suppresses the normal change of directory when rotating or adding directories to the stack, so that only the stack is manipulated.

+N

Brings the Nth directory (counting from the left of the list printed by dirs OR counting from the top down of the list printed by dirs -v, starting with zero) to the top of the list by rotating the stack.

–N

Brings the Nth directory (counting from the right of the list printed by dirs OR counting from the bottom up of the list printed by dirs -v, starting with zero) to the top of the list by rotating the stack.

dir

Makes dir be the top of the stack, making it the new current directory as if it had been supplied as an argument to the cd builtin

Bash Directory Stack Commands 

The first command we will look at is the pushd command. This command is a Bash builtin which can, in effect, replace the cd command in the Terminal. To demonstrate the use case for this command’s replacement of the cd command, let’s traverse to a couple of directories and sub-directories which I have created on my system. If I start at the ~/ dstack directory and run a listing of its sub-directory and the child directory of the directory with a very long name, we see the following output listing: 

datapioneer@ferenOS-MainPC:~$ ls dstack/this-is-a-very-long-directory-name/and-amore-pointless-subdirectory/ 

then if I cd into that directory structure and follow that with a pwd command to print that current working directory, we will get: 

datapioneer@ferenOS-MainPC:~/dstack/this-is-a-very-long-directory-name/and-a-morepointless-subdirectory

Therefore, if my directory stack contains a very long sub-directory name followed by another sub-directory with a very long pointless name as well, it is difficult to work in these directories if I have to move back and forth between them. Now, let’s assume that while working in the current working directory, I decide that I need to traverse into a /etc/ssh directory to check some settings for ssh. I could use the cd command to accomplish this, but instead, I’m going to use the pushd command. So, if I issue the command: pushd /etc/ssh at this point, I will get the following output instead: 

datapioneer@ferenOS-MainPC:~/dstack/this-is-a-very-long-directory-name/and-a-morepointless-subdirectory$ pushd /etc/ssh/
/etc/ssh ~/dstack/this-is-a-very-long-directory-name/and-a-more-pointlesssubdirectory 

Unlike what I would get if I had issued the cd command, pushd gives me not only the directory listing of my pwd but also the directory I landed in, which is /etc/ssh. So, if I’m working in /etc/ssh and need to go back to my previous directory, I would have to cd back into the previous directory which contains my ~/dstack/this-is-a-very-long-directoryname/and-a-more-pointless-subdirectory or tab complete to get there. And, if I switched back and forth several times working on a project in that directory, it would become very painful to do so on a recurring basis. Now, if I invoke another bash directory command, dirs, and use the -v modifier along with it, I get a very nice listing of these two directories in a vertical printout and it is indexed. Let’s take a closer look by running the following command: 

datapioneer@ferenOS-MainPC:/etc/ssh$ dirs -v 0 /etc/ssh
1 ~/dstack/this-is-a-very-long-directory-name/and-a-more-pointless-subdirectory

So, you can clearly see that what I’m given as a display is the directory stack consisting of my pwd which is indexed as 0 and the previous pwd which is indexed as 1. Here, the dirs command stands for directory stack and the -v modifier is the vertical listing modifier which also indexes the directory printout nicely for us. One thing to remember here as well is that the 0 index directory is always your current pwd. Now, if I need to switch back to my project directory, which is shown as index 1 above, then I can easily accomplish this by invoking yet another Bash directory stack command, popd, like so:

datapioneer@ferenOS-MainPC:/etc/ssh$ popd
~/dstack/this-is-a-very-long-directory-name/and-a-more-pointless-subdirectory
datapioneer@ferenOS-MainPC:~/dstack/this-is-a-very-long-directory-name/and-a-morepointless-subdirectory$ dirs -v
0 ~/dstack/this-is-a-very-long-directory-name/and-a-more-pointless-subdirectory

which pops me back into my project directory and removes the previous 0 index and replaces it with the new 0 index, as shown, which is now my pwd. Thus by replacing cd with pushd, this was a very easy and painless process and great example for a use case for the bash directory stack in Linux. So, for example, to demonstrate the usefulness of the pushd command even more, I have created a directory stack as follows: 

datapioneer@ferenOS-MainPC:~$ dirs -v
0 ~
1 ~/Downloads
2 ~/Music
3 ~/Pictures
4 ~/Videos

where the index of 0 represents my pwd as confirmed in the first line. I’ve run the dirs -v to list out the directory stack so the printout is vertical and indexed as shown. Now, let’s assume that I want to move into the ~/Music directory from here. I could do that with cd, but instead, I’m going to use the pushd command followed by the +N option, where N = 2, like so: 

datapioneer@ferenOS-MainPC:~$ pushd +2
~/Music ~/Pictures ~/Videos ~ ~/Downloads
datapioneer@ferenOS-MainPC:~/Music$ dirs -v
0 ~/Music
1 ~/Pictures
2 ~/Videos 3 ~
4 ~/Downloads

And, if I repeat the dirs -v command to get the vertically-listed printout with indexes, I see that more than simply moving into the ~/Music directory (which, as you recall, is indicated by a 0 index), but the directory stack has also been rotated with every directory below ~/Music (in the previous 2 position) being rotated above and under the ~/Music directory, and every directory that was previously above the 2 position has now been pushed down below. The new directory stack is displayed above. Thus, the directory stack’s array elements remain the same, just rotated with the original 0 indexed position represented by the ~ above moving to the 3rd index position with ~/Downloads under it and all the other directories rotated above in the same order they were in before rotation. No directories have been deleted in the directory stack. If, instead, we want to remove a directory from the stack, then we can return to our popd command to accomplish this since pushd will only rotate the stack, not remove elements from it. Therefore, looking at the indexed list of directories above, if I wanted to remove the ~/Pictures directory from the stack, I could easily accomplish this by issuing the command:

datapioneer@ferenOS-MainPC:~/Music$ popd +1
~/Music ~/Videos ~ ~/Downloads
datapioneer@ferenOS-MainPC:~/Music$ dirs -v
0 ~/Music
1 ~/Videos
2 ~
3 ~/Downloads

which results in the removal of the ~/Pictures directory leaving directories corresponding to indices 0, 1, 2, and 3 remaining since the ~/Pictures directory was in the first (+1) position counting from 0 and is marked by a 1 off to the left of that directory in the indexed vertical listing before we issued the popd +1 command. Now, if we repeat the popd command once again but this time use a -0 modifier, we should effectively start at the bottom of the indexed list and remove the last item on that list, which is the ~/Downloads. Issuing the command in the Terminal to verify this, we obtain:

datapioneer@ferenOS-MainPC:~/Music$ popd -0
~/Music ~/Videos ~
datapioneer@ferenOS-MainPC:~/Music$ dirs -v
0 ~/Music
1 ~/Videos
2 ~

Another very important directory stack command is the dirs -c command which clears the stack. So, if I want to completely wipe out my directory stack and return to the pwd (index 0) as the only entry in the stack, I would accomplish this by issuing the command:

datapioneer@ferenOS-MainPC:~/Music$ dirs -v
0 ~/Music
1 ~/Videos
2 ~
datapioneer@ferenOS-MainPC:~/Music$ dirs -c
datapioneer@ferenOS-MainPC:~/Music$ dirs -v
0 ~/Music

which wipes out the directory stack list and leaves ~/Music as my pwd directory. So, if you move about the directories in Linux on a quite frequent basis, especially if you have a project directory that you are moving into and out of quite a bit, the bash directory stack commands will quickly become your friend. And, finally, let’s look at a last more advanced use case for the bash directory stack builtins.

Example Advanced Use Case

If you know you’re going to be in several directories on your Linux system including your project directory and will be moving in and out of each of these directories on a frequent basis, what you can do is edit your ~/.bashrc file and add those directories at the bottom with the pushd prefix in front of each of them so that when you logout of the system or restart it, you will have those directories loaded automatically for you in the bash directory stack.

# add Mongodb to the $PATH variable
204 export PATH="/home/datapioneer/mongodb-linux-x86_64-ubuntu1804-4.4.1/bin:$PATH" 
205 
206 # pushd directories created for convenience 
207
208 pushd /home/datapioneer/Videos
209 pushd /home/datapioneer/Music
210 pushd /home/datapioneer/Pictures
211 pushd /home/datapioneer/dstack

So, in the block above, you are looking at the bottom few lines of my ~/.bashrc file where I am editing that file using nano to add lines 206 through 211, which includes my project directory of ~/dstack. By editing the ~/.bashrc file in this manner and saving the file, the Bash directory stack will be automatically loaded each time I log in. So, if I log out and back in the system, what I see is the following:

datapioneer@ferenOS-MainPC:~/$
~/Videos ~
~/Music ~/Videos ~
~/Pictures ~/Music ~/Videos ~
~/dstack ~/Pictures ~/Music ~/Videos ~
datapioneer@ferenOS-MainPC:~/dstack$ dirs -v
0 ~/dstack
1 ~/Pictures
2 ~/Music
3 ~/Videos
4 ~
datapioneer@ferenOS-MainPC:~/dstack$

The pushd commands were loaded on login or reboot and if I run the dirs -v command, I see the Bash directory stack has been created for me placing me automatically in the ~/dstack (project directory). And, so, for instance, if after logging in and getting all my “hot” directories loaded in the stack for me, I want to move quickly into the ~/Videos directory, all I have to do is issue the pushd command:

datapioneer@ferenOS-MainPC:~/dstack$ pushd +3
~/Videos ~ ~/dstack ~/Pictures ~/Music
datapioneer@ferenOS-MainPC:~/Videos$ dirs -v
0 ~/Videos
1 ~
2 ~/dstack
3 ~/Pictures
4 ~/Music
datapioneer@ferenOS-MainPC:~/Videos$

and the directory stack gets rotated landing me in my desired ~/Videos directory with all the other directories being rotated as shown above. Now that you understand the Bash directory stack and some of the things you can do with it, you should be able to move much more quickly through the directory hierarchy on your Linux system and your daily workflow will be much improved and, just maybe, you will impress some folks along the way.

Notes & References

Michael S. Mahoney , ”What Was the Question? The Origins of the Theory of Computation”. Using History to Teach Computer Science and Related Disciplines.  Selected Papers from a Workshop, ed. Atsushi Akera and William Aspray (Washington, D.C.: Computer Research Association, 2004), pp. 225-232