スタートアップCTOによるITエンジニアのためのブログ

Bashのpushdとpopdを使って複数ディレクトリで作業しよう

「さっきのディレクトリに戻りたいけど、パスが長くて打ち直すのが面倒」「複数のプロジェクトディレクトリを頻繁に行き来したい」……。そんな悩みを解決するのが、Bashの組み込みコマンドである pushdpopd です。

単なる cd よりもスマートに移動を管理し、作業効率を劇的に向上させる方法を紹介します。

目次

  • pushdとpopdの概要
  • ディレクトリスタックとは
  • dirsでスタックを閲覧する
  • pushdでスタックに追加・移動
  • popdでスタックから削除
  • cdとの比較:なぜpushd/popdを使うのか?
  • インタラクティブシェルでの活用方法
  • シェルスクリプトでの活用方法
  • まとめ

pushdとpopdの概要

一言で言えば、「ディレクトリの履歴を積み上げて管理できるcd」です。

  • pushd: 指定したディレクトリに移動しつつ、現在の場所を「スタック」に保存します。
  • popd: スタックから最後に保存したディレクトリを取り出し、そこへ戻ります。

ディレクトリスタックとは

「スタック(Stack)」とは、本を積み上げるようなデータ構造のことです。新しく追加したものが一番上に乗り、取り出すときは一番上(最新のもの)から順に取っていきます。

このような管理方法は後入れ先出し、英語でLast In First Out (LIFO)と呼ばれます。

Bashはこの仕組みを利用して、訪れたディレクトリを順番に記録しています。直近の場所から順番に 0, 1, 2... というインデックス番号が割り当てられます。

インデックス0は常に「現在のディレクトリ」を指します。たとえ cd で移動したとしても、インデックス0の内容は常に更新されます。

インデックス0が流動的なため、実質的なディレクトリの保存はインデックス1以降で行います。

豆知識:ディレクトリスタックは DIRSTACK という配列変数に格納されています。

ディレクトリスタック構造とpushdとpopd

dirsでスタックを閲覧する

現在スタックにどのディレクトリが積まれているかを確認するには、dirs コマンドを使います。

# Bash
dirs -v

# 出力例
# 0  /var
# 1  /etc
# 2  ~

-v オプションを付けると、インデックス番号(0, 1, 2…)付きでリスト表示されるため、非常に見やすくなります。

スタックをリセット(インデックス0以外を消去)するには -c オプションを使います。

# Bash
dirs -c

pushdでスタックに追加・移動

pushd は引数の有無で挙動が変わります。

1. 引数を指定する場合

pushd /path/to/dir と打つと、以下の順番でスタック変更とディレクトリ移動が行われます。

  1. 現在のディレクトリ(インデックス0)をインデックス1にし、スタックに保存(プッシュ)する。
  2. 指定したディレクトリへ移動し、それが新たなインデックス0(先頭)になる。
# Bash
pwd # 出力:/etc
# 現在地をスタックに保存して指定ディレクトリに移動
pushd /var # 出力 /var /etc
pwd # 出力 /var

移動なしでスタックへ追加:-n オプション

「移動はしたくないが、後で使うために登録だけしたい」場合は -n が便利です。 pushd -n /path/to/dir とすると、カレントディレクトリはそのままに、指定パスをインデックス1に追加します。

スタックを回転させて移動:+n オプション

pushd +n (nは番号)と打つと、スタックを回転(ローテーション)させます。n番目の要素を先頭(インデックス0)に持ってくるように、リスト全体をずらして移動します。

2. 引数なしの場合

pushd を単体で実行すると、インデックス0と1を入れ替えます。

つまり、「今いる場所」と「一つ前にいた場所」を交互に行き来するのに最適です。

# Bash
dirs # 出力: /var /etc
# インデックスの0と1を入れ替え
pushd # 出力: /etc /var
# インデックス0に移動している
pwd # 出力: /etc

もしインデックス1が存在しない場合、入れ替えを行えずエラーになります。

# Bash
# スタックが空
dirs # 出力: /etc
pushd # エラー出力:-bash: pushd: 他のディレクトリはありません

popdでスタックから削除

作業が終わって元の場所に戻りたいときは、popd を使います。

  1. スタックの一番上(インデックス0)を削除します。
  2. 新しいインデックス0(元々のインデックス1)のディレクトリへ自動的に移動します。
# Bash
pwd # 出力: /home
dirs # 出力: /home /var /etc
popd # 出力: /var /etc
pwd # 出力: /var

移動なしで特定の履歴を削除:+n オプション

「今いる場所は変えずに、スタックにある3番目の履歴だけ消したい」という時は popd +3 のように指定します。

# Bash
pwd # 出力: /home
dirs # 出力: /home /var /etc
# インデックス2を削除
popd +2 # 出力: /home /var
# 現在のディレクトリは元のまま
pwd # 出力: /home
  • 厳密にはスタックの先頭に移動しますが、+0で先頭を削除しない限りはカレントディレクトリは元のディレクトリのままです(cd .と同じ)。
  • 本当に移動せず、インデックス1を削除する-nというオプションもありますが、+nで削除するインデックス番号を指定する方が柔軟です。

cdとの比較:なぜpushd/popdを使うのか?

cd - でも一つ前のディレクトリには戻れますが、3つ以上の場所を行き来する際に限界が来ます。

機能cdpushd / popd
記憶できる数直近の1つのみ(cd -メモリが許す限り無膳
管理方法単なる往復構造的なスタック管理
柔軟性3地点以上の移動は困難番号指定でどこへでも戻れる

応用:cdとスタック参照の組み合わせ

実は cd コマンドでも、スタックの番号を使って移動できます。 cd ~+2 と打てば、スタックの2番目にあるディレクトリに(スタック構造を変えずに)移動可能です。

~+2 のようにスタック参照する方法はチルダ展開と呼ばれ、「Bashチルダ展開(Tilde Expansion)による高速ディレクトリ操作」で詳しく解説しています。

インタラクティブシェルでの活用方法

ターミナルでの作業中、特定のディレクトリを「ブックマーク」のように扱えます。

MVCフレームワークでの例

# Bash
pushd -n app/models
pushd -n app/views
pushd -n app/controllers

これで、dirs -v を確認しながら pushd +2cd ~+1 で各層を自由に行き来できます。

Bash設定ファイルへの記載

よく使うプロジェクトパスを .bashrc に書いておけば、起動時から「戻れる場所」がセットされます。

# Bash
# .bashrc
pushd -n "${HOME}/my_project" > /dev/null

シェルスクリプトでの活用方法

スクリプト内で一時的にディレクトリを移動する場合、cd だとエラーが起きた際に元の場所を見失うリスクがあります。

# Bash
# シェルスクリプト内での例
function backup_data() {
    # 移動してスタックに積む
    if ! pushd /var/log > /dev/null; then
        echo "エラー: ディレクトリに移動不可"
        return 1
    fi
    tar -zcvf logs.tar.gz *.log
    # 確実に元のディレクトリに戻る
    popd > /dev/null
}

このように pushdpopd をペアで使うことで、スクリプト終了後にユーザーを迷子にさせない、堅牢なコードになります。

まとめ

  • ディレクトリスタックは後入れ先出し(LIFO)の構造。
  • pushd は「現在地を保存して移動」、popd は「削除して戻る」。
  • pushdpopdも、移動先がスタックの先頭になる。
  • dirs -v で現在のスタックを常に把握できる。

これらを使いこなすだけで、ターミナル作業のストレスは大幅に軽減されます。まずは「cd の代わりに pushd を使ってみる」ことから始めてみてはいかがでしょうか。