5

I am a happy user of the cd - command to go to the previous directory. At the same time I like pushd . and popd.

However, when I want to remember the current working directory by means of pushd ., I lose the possibility to go to the previous directory by cd -. (As pushd . also performs cd .).

How can I use pushd to still be able to use cd -

By the way: GNU bash, version 4.1.7(1)

Bernhard
  • 11,992
  • 4
  • 59
  • 69
  • 1
    Why not use `pwd` to figure out where you are? – phemmer Feb 21 '12 at 12:39
  • I don't understand your question? The point is that pushd breaks the behavior of `cd -` that I want (or expect). I know perfectly well in which directory I am, but I want to increase the speed with which I change directories :) – Bernhard Feb 21 '12 at 12:46
  • You waid "when I want to remember the current working directory by means of `pushd .`". If you want to remember the current working directory, thats what `pwd` is for. – phemmer Feb 21 '12 at 13:49
  • @Patrick But this is information is lost when I change directories again. – Bernhard Feb 21 '12 at 14:36
  • 1
    Do you know `zsh`? It has really nice features like AUTO_PUSHD. – jofel Feb 21 '12 at 14:39
  • 3
    +1 Thank you for teaching me about cd -! For most of a decade, I've been doing $ cd $OLDPWD instead. – Theodore R. Smith Feb 21 '12 at 16:26
  • 1
    @bernhard Oh, I misunderstood what you were asking. You were wanting to know how to *store* the current working directory. I was interpreting it as you wanted to remember (as in you forgot) your current working directory. – phemmer Feb 22 '12 at 01:58

3 Answers3

7

You can use something like this:

push() { 
    if [ "$1" = . ]; then
        old=$OLDPWD
        current=$PWD
        builtin pushd .
        cd "$old"
        cd "$current"
    else
        builtin pushd "$1"
    fi
}

If you name it pushd, then it will have precedence over the built-in as functions are evaluated before built-ins.

You need variables old and current as overwriting OLDPWD will make it lose its special meaning.

Wildcard
  • 35,316
  • 26
  • 130
  • 258
Wojtek
  • 2,290
  • 2
  • 17
  • 24
  • This works perfectly for me. Is there no such feature in the built-in pushd? As I would always prefer a standard solution. Thanks for this function however, maybe I will leave out the argument and it's checking at some point. – Bernhard Feb 21 '12 at 12:41
  • There is no such feature in the builtin. Your own function is the best solution because pushd and popd both call `cd` modifying $OLDPWD, hence the source of your problem. I would name the function saved and use it in the context you like too, that of saving cwd. – bsd Feb 21 '12 at 12:53
  • You might also want to unset `old` and `current` after you're done with them. – Wildcard Mar 29 '16 at 23:08
3

A slightly more concise version of Wojtek's answer:

pushd () {
        if [ "$1" = . ]; then
                cd -
                builtin pushd -
        else    
                builtin pushd "$1"
        fi      
}

By naming the function pushd, you can use pushd as normal, you don't need to remember to use the function name.

Kevin
  • 40,087
  • 16
  • 88
  • 112
0

Kevin's answer is excellent. I've written up some details about what's going on, in case people are looking for a better understanding of why their script is necessary to solve the problem.

The reason that pushd . breaks the behavior of cd - will be apparent if we dig into the workings of cd and the directory stack. Let's push a few directories onto the stack:

$ mkdir dir1 dir2 dir3
$ pushd dir1
~/dir1 ~
$ pushd../dir2
~/dir2 ~/dir1 ~
$ pushd../dir3
~/dir3 ~/dir2 ~/dir1 ~
$ dirs -v
0       ~/dir3
1       ~/dir2
2       ~/dir1
3       ~

Now we can try cd - to jump back a directory:

$ cd -
/home/username/dir2
$ dirs -v
0       ~/dir2
1       ~/dir2
2       ~/dir1
3       ~

We can see that cd - jumped us back to the previous directory, replacing stack ~0 with the directory we jumped into. We can jump back with cd - again:

$ cd -
/home/username/dir3
$ dirs -v
0       ~/dir3
1       ~/dir2
2       ~/dir1
3       ~

Notice that we jumped back to our previous directory, even though the previous directory wasn't actually listed in the directory stack. This is because cd uses the environment variable $OLDPWD to keep track of the previous directory:

$ echo $OLDPWD
/home/username/dir2 

If we do pushd . we will push an extra copy of the current directory onto the stack:

$ pushd . 
~/dir3 ~/dir3 ~/dir2 ~/dir1 ~
$ dirs -v
0       ~/dir3
1       ~/dir3
2       ~/dir2
3       ~/dir1
4       ~

In addition to making an extra copy of the current directory in the stack, pushd . has updated $OLDPWD:

$echo $OLDPWD
/home/username/dir3

So cd - has lost its useful history, and will now just move you to the current directory - accomplishing nothing.

Spark
  • 11
  • 2