When I use popd alone it removes a directory from the stack and takes me to that directory. However, if I do cd $(popd) then no directory is removed from the stack.

Since the process is simply forked and the result is put in place of the shell expansion, why isn't a directory taken off of the stack?


The command substitution $(…) runs the command in a subshell. A subshell starts out as an identical¹ copy of the main shell, but from that point on the main shell and the subshell live their own life.

  1. The shell process creates a pipe and forks.
  2. The child runs popd with its output connected to the pipe, then exits.
  3. The parent reads the data from the pipe and substitutes it into the command line.

Since popd runs in the child process, its effect is limited to the child process. The directory is taken off the stack — off the child's stack. Nothing happens to the stack in the parent.

¹ Nearly identical; the differences are not relevant here.


The syntax $(...) isn't "shell expansion", it is "command substitution".

With this syntax a sub-shell is created, the command inside is executed and the stdout returned on the comamnd line. So, for example,

x=$(cd /tmp ; ls)

will run the cd command in the subshell, which means the current directory of the main process is left untouched.

In a similar way, cd $(popd) will cause the popd to run in the child process and so impacts only the child process; the parent process is untouched.

You can see that it has affected the child process with this simple test:

$ pushd /tmp
/tmp ~
$ pushd /
/ /tmp ~
$ dirs
/ /tmp ~
$ cd $(popd ; dirs >&2)
/tmp ~
$ dirs
/tmp /tmp ~

The dirs >&2 shows that inside the $(...) shell the directory stack has been popped, but because this is a child process the parent stack is untouched.

  • 4
    Nitpick: $(…) is shell expansion — specifically, it's the part of shell expansion that is called command substitution. – Gilles 'SO- stop being evil' Aug 8 '16 at 23:54

pushd and popd keep the stack in a variable called DIRSTACK, which changes in your subshell, but stays unchanged in the parent shell, just like any other environment variable.

Further read.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.