opscape

Shell builtins · bash builtin

pushd

Change to a directory and remember the previous one on a stack, so popd can return to it.

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

8 of 8 examples run in Debian 13.7 on 2026-10-31 · manual: bash(1), SHELL BUILTIN COMMANDS

bash keeps a directory stack: a list of directories whose top entry is always the current one. pushd DIR changes to DIR and pushes it on top, keeping the old directory underneath. popd removes the top entry and changes back to the one below. dirs shows the stack; dirs -v numbers the entries, which is what +N arguments refer to.

Compared with cd -, which remembers only one previous directory, the stack can hold any number, and pushd with no argument swaps the top two, toggling between two places. In scripts it is a readable way to "go there, do something, come back", although a subshell ( cd dir && cmd ) is often simpler and cannot forget to return.

pushd and popd print the whole stack after every change. That is helpful at the prompt and noise in a script, so scripts usually add >/dev/null.

Examples

Change directory and remember where you were

pushd data
pwd
pushd ../logs
dirs -v
output
~/demo/data ~/demo
/home/dev/demo/data
~/demo/logs ~/demo/data ~/demo
 0  ~/demo/logs
 1  ~/demo/data
 2  ~/demo

Each pushd prints the stack with the new current directory first. ~ abbreviates /home/dev. dirs -v shows one entry per line with its index; entry 0 is always the current directory.

Go somewhere and come back with popd

pushd /etc >/dev/null
echo "now in $PWD"
popd >/dev/null
echo "back in $PWD"
output
now in /etc
back in /home/dev/demo

popd removes the top entry and returns to the directory below it. The redirection silences the stack printout, which is the usual style in scripts.

Toggle between two directories

pushd src >/dev/null
pushd >/dev/null; echo "1: $PWD"
pushd >/dev/null; echo "2: $PWD"
pushd >/dev/null; echo "3: $PWD"
output
1: /home/dev/demo
2: /home/dev/demo/src
3: /home/dev/demo

With no argument, pushd swaps the two top entries and changes to the new top, so each call flips between demo and demo/src.

Rotate the stack with +N

pushd /tmp >/dev/null; pushd /etc >/dev/null; pushd /usr >/dev/null
dirs -v
pushd +2 >/dev/null
echo "after pushd +2:"
dirs -v
output
 0  /usr
 1  /etc
 2  /tmp
 3  ~/demo
after pushd +2:
 0  /tmp
 1  ~/demo
 2  /usr
 3  /etc

pushd +N rotates the stack so that entry N (counted from 0 at the top, as dirs -v shows) comes to the top, and changes there. The other entries keep their cyclic order.

Add a directory without changing to it

pushd -n /var/log >/dev/null
pwd
dirs -v
output
/home/dev/demo
 0  ~/demo
 1  /var/log

-n adds the directory to the stack (second place, just below the current directory) but stays put. A later pushd +1 or popd can jump there.

Pushing a directory that does not exist

pushd no-such-dir
echo "status $?, still in $PWD"
output
/bin/bash: line 1: pushd: no-such-dir: No such file or directory
status 1, still in /home/dev/demo

Nothing is pushed and the current directory does not change; pushd returns 1. In a script, use pushd dir || exit so later commands do not run in the wrong place.

Run commands in another directory in a script

build.sh
#!/usr/bin/env bash
set -e
pushd src >/dev/null
echo "building in $PWD"
ls *.c
popd >/dev/null
echo "back in $PWD"
bash build.sh
explain
output
building in /home/dev/demo/src
main.c
back in /home/dev/demo

The commands between pushd and popd run inside src, then the script returns to where it was. With set -e, an error between them would exit without the popd, which is fine in a script but a reason to prefer ( cd src && ... ) in a function.

The subshell alternative

( cd src && ls *.c )
echo "still in $PWD"
output
main.c
still in /home/dev/demo

A subshell has its own current directory, so the cd cannot leak out, even if a command fails. Use this when nothing from inside needs to change the parent's variables.

Common pitfalls

  • Forgetting to silence pushd/popd in scripts; they print the stack on every call. Redirect stdout to /dev/null.

  • Unchecked pushd: if the directory is missing, the script keeps running in the old one. Write pushd dir >/dev/null || exit 1.

  • Mixing cd and pushd: cd replaces the top of the stack instead of pushing, so a later popd returns somewhere you did not expect.

  • The stack belongs to the current shell. A pushd inside $(...), a pipeline or a script you run does not affect your terminal.

GNU vs BSD and macOS

The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).

  • pushd, popd and dirs are not POSIX and dash does not have them; #!/bin/sh scripts fail with pushd: not found. bash and zsh both have them, with zsh adding options such as AUTO_PUSHD.

Options worth knowing

A selection, described in our own words. For the full list, see bash(1), SHELL BUILTIN COMMANDS.

OptionWhat it does
-nAdd the directory to the stack without changing to it.

Related