4.5 Advanced Examples: pushd and popdWe will conclude this chapter with a couple of functions that you may find handy in your everyday UNIX use. Task 4.7
We will start by implementing a significant subset of their capabilities and finish the implementation in Chapter 6 . If you don't know what a stack is, think of a spring-loaded dish receptacle in a cafeteria. When you place dishes on the receptacle, the spring compresses so that the top stays at roughly the same level. The dish most recently placed on the stack is the first to be taken when someone wants food; thus, the stack is known as a "last-in, first-out" or LIFO structure. [15] Putting something onto a stack is known in computer science parlance as pushing , and taking something off the top is called popping .
A stack is very handy for remembering directories, as we will see; it can "hold your place" up to an arbitrary number of times. The cd - form of the cd command does this, but only to one level. For example: if you are in firstdir and then you change to seconddir , you can type cd - to go back. But if you start out in firstdir , then change to seconddir , and then go to thirddir , you can use cd - only to go back to seconddir . If you type cd - again, you will be back in thirddir , because it is the previous directory. [16]
If you want the "nested" remember-and-change functionality that will take you back to firstdir , you need a stack of directories along with the pushd and popd commands. Here is how these work: [17]
For example, consider the series of events in Table 4.6 . Assume that you have just logged in, and that you are in your home directory ( /home/you ). We will implement a stack as an environment variable containing a list of directories separated by spaces.
Your directory stack should be initialized to the null string when you log in. To do this, put this in your .profile :
DIRSTACK="" export DIRSTACK Do not put this in your environment file if you have one. The export statement guarantees that DIRSTACK is known to all subprocesses; you want to initialize it only once. If you put this code in an environment file, it will get reinitialized in every subshell, which you probably don't want. Next, we need to implement pushd and popd as functions. Here are our initial versions:
function pushd { # push current directory onto stack dirname=$1 cd ${dirname:?"missing directory name."} DIRSTACK="$dirname ${DIRSTACK:-$PWD}" print "$DIRSTACK" } function popd { # pop directory off stack, cd to new top DIRSTACK=${DIRSTACK#* } cd ${DIRSTACK%% *} print "$PWD" } Notice that there isn't much code! Let's go through the two functions and see how they work, starting with pushd . The first line merely saves the first argument in the variable dirname for readability reasons.
The second line's main purpose is to change to the new directory.
We use the
The third line of the function pushes the new directory onto the
stack.
The expression
${DIRSTACK
The last line merely prints the contents of the stack, with the implication that the leftmost directory is both the current directory and at the top of the stack. (This is why we chose spaces to separate directories, rather than the more customary colons as in PATH and MAILPATH.)
The
popd
function makes yet another
use of the shell's pattern-matching operators.
Its first line uses the
#
operator, which tries to delete
the shortest match of the pattern "
The second line of
popd
uses the pattern-matching operator
%%
to delete the
longest
match to the pattern " This code is deficient in three ways: first, it has no provision for errors. For example:
Test your understanding of the code by figuring out how it would respond to these error conditions. The second deficiency is that it implements only some of the functionality of the C shell's pushd and popd commands-albeit the most useful parts. In the next chapter, we will see how to overcome both of these deficiencies. The third problem with the code is that it will not work if, for some reason, a directory name contains a space. The code will treat the space as a separator character. We'll accept this deficiency for now. However, when you read about arrays in Chapter 6 , Command-line Options and Typed Variables , think about how you might use them to rewrite this code and eliminate the problem. |
|