Skip to content
Linux Basics: Revisit Working Directories with Bash Directory Stacks

Linux Basics: Revisit Working Directories with Bash Directory Stacks

October 22, 2026

A script may need to enter a build directory, inspect another folder, and return without guessing how many .. components to use. Bash’s directory stack keeps an ordered list of locations. Practice returning, selecting a saved entry, and checking failed navigation.

These examples were tested on Linux with GNU Bash 5.2.37. Use Bash rather than sh. The first two scripts create differently named practice directories. Run each once before cleanup; an existing directory causes its setup to stop.

Prepare a scratch directory

You need Bash, a text editor, and the mkdir, mktemp, rm, and rmdir utilities. Keep using the same terminal. Save each named source file in this directory before running it. The guards stop setup if it fails; invoking bash explicitly avoids changing executable permissions. No administrator access is needed.

start_dir="$PWD"
work_dir="$(mktemp -d)" || exit 1
cd -- "$work_dir" || exit 1

1. Return after working in a nested directory

Save this as stack-return.sh:

#!/usr/bin/env bash
unset CDPATH
dirs -c
origin=$PWD
mkdir -- stack-return || exit 1
mkdir -- 'stack-return/build output' || exit 1
pushd "$origin/stack-return/build output" >/dev/null || exit 1
printf 'Working in: %s\n' "${PWD##*/}"
popd >/dev/null || exit 1
if [[ $PWD == "$origin" ]]; then
  printf 'Returned to the starting directory\n'
else
  exit 1
fi

Run it:

bash stack-return.sh

Output:

Working in: build output
Returned to the starting directory

pushd saves the previous location while entering the requested directory. popd removes the current stack entry and returns to the next one. Both operations are checked before the script continues.

The builtins normally print the resulting stack; redirecting that listing to /dev/null leaves just the useful progress messages. The quoted absolute path handles the space in build output. This script does not create a build or change project files: its small directory tree is a stand-in for a real build location.

2. Inspect and select a saved location

Save this as stack-select.sh:

#!/usr/bin/env bash
unset CDPATH
mkdir -- stack-select || exit 1
mkdir -- stack-select/source stack-select/reports || exit 1
cd -- stack-select || exit 1
dirs -c
base=$PWD
pushd "$base/source" >/dev/null || exit 1
pushd "$base/reports" >/dev/null || exit 1
saved=$(dirs -l +1) || exit 1
printf 'Entry +1: %s\n' "${saved##*/}"
pushd +1 >/dev/null || exit 1
printf 'After rotation: %s\n' "${PWD##*/}"
popd +1 >/dev/null || exit 1
printf 'After removing +1: %s\n' "${PWD##*/}"
printf 'Entries remaining: %s\n' "${#DIRSTACK[@]}"

Run it:

bash stack-select.sh

Output:

Entry +1: source
After rotation: source
After removing +1: source
Entries remaining: 2

Indexes start at zero, with the current directory at +0. Here dirs -l +1 retrieves the next entry as a full pathname. Only its last component is printed so the transcript does not depend on the random scratch path.

After pushd +1, the order is source, stack-select, reports. Removing entry +1 therefore discards stack-select without leaving source. DIRSTACK exposes the stack as an array, so its length confirms that two entries remain. For an interactive overview, dirs -v lists entries with their indexes. Recheck indexes after every rotation or removal.

3. Handle a missing destination and an empty saved stack

Save this as stack-errors.sh:

#!/usr/bin/env bash
unset CDPATH
dirs -c
origin=$PWD
if pushd ./stack-missing >/dev/null 2>&1; then
  printf 'Unexpected destination\n'
  exit 1
else
  printf 'Missing directory: navigation refused\n'
fi
if popd >/dev/null 2>&1; then
  printf 'Unexpected saved entry\n'
  exit 1
else
  printf 'No saved directory to return to\n'
fi
[[ $PWD == "$origin" ]] || exit 1
printf 'Working directory unchanged\n'

Run it:

bash stack-errors.sh

Output:

Missing directory: navigation refused
No saved directory to return to
Working directory unchanged

dirs -c removes saved entries without changing the current directory. With no other entries available, popd fails. The missing destination also produces a failure, and the final comparison verifies that neither operation moved the script.

The example suppresses the builtins’ diagnostics because it prints its own stable messages. Keep standard error visible when diagnosing unexpected failures. A remembered pathname is not a guarantee that its directory still exists or remains accessible.

Keep in mind

These scripts run in separate Bash processes, so their directory stacks and directory changes do not alter the terminal that launched them. For interactive navigation, run the builtins directly in your Bash terminal. Avoid sourcing these demonstrations into a working shell: they deliberately clear the stack.

Clean up

In the same terminal, remove only the named practice files, return to your original directory, and remove the empty scratch directory:

rmdir -- 'stack-return/build output' stack-return
rmdir -- stack-select/source stack-select/reports stack-select
rm -- stack-return.sh stack-select.sh stack-errors.sh
cd -- "$start_dir" || exit 1
rmdir -- "$work_dir"
unset start_dir work_dir

References

Acknowledgements

This post was created with assistance from AI.

Last updated on