ディレクトリの移動は cd コマンドよりも pushd コマンドのほうが便利！

コマンドラインで作業するときにおそらく一番目か二番目によく使うのが cd コマンド。たった 2 文字しかないので打つのも簡単です。しかし、深い高層のディレクトリ間を頻繁に移動するときに毎回ディレクトリを指定するのが面倒なことがあります。

下のディレクトリツリーを例に取ります。
![ディレクトリツリー.png](https://qiita-image-store.s3.amazonaws.com/0/113895/2b35d7ed-c0bc-bd3f-102b-0c9cbcac89cb.png)

カレントディレクトリが workspace1/html だったとします。ここから workspace2/html に移動したい場合は `cd ../../workspace2/html` と入力します。そして今度は workspace1/js に移動したくなったら `cd ../../workspace1/js` と入力します。workspace2/js に移動したくなったら `cd ../../workspace2/js` と入力……ちょっと面倒ですよね。

このツリー構造はそこまで深くないので workspace1 内のディレクトリから workspace2 のディレクトリに移動しようと思ったら ../../workspace... だけでいいですが、フレームワークを使っていたりするともっと階層が深くなり、../../../../workspace... のようになり、.. を打つだけでも大変です。

# ディレクトリスタックを使おう！
ディレクトリスタックとは、ディレクトリの位置をフルパスで複数保存しておくためのスタック(記憶領域)です。ディレクトリスタックにディレクトリのパスを保存するには `pushd`、ディレクトリスタックの状態を確認するには `dirs`、ディレクトリスタックのパスを削除するには `popd` を使います。

実際に試してみましょう。先に紹介したツリー構造で、workspace1/html にいるとします。ここで、`cd` コマンドの代わりに `pushd` コマンドを使用して、workspace2/html に移動します。
`$ pushd ../../workspace2/html`
これで、workspace2/html に移動し、workspace1/html へのフルパスがスタックに積まれました。`dirs` で確認してみましょう。

```
$ dirs
0  ~/workspace2/html
1  ~/workspace1/html
```
ここでもう一度、`pushd` を実行すると、workspace2/html から workspace1/html に移動できます。さらに `pushd` を実行すると workspce2/html にまた戻ってくることができます。

# どういう仕組みなのか？
`pushd` コマンドは、カレントディレクトリのフルパスをディレクトリスタックに積んで、指定した引数のディレクトリに移動するコマンドです。移動先のディレクトリを指定せずに単に `pushd` だけで実行した場合は直前にいたディレクトリに移動できます。

```
$ pwd
~/workspace1/html
$ dirs
0 ~/workspace1/html　# カレントディレクトリが 0 番目に積まれている
$ pushd ../../workspace2/html
$ dirs
0 ~/workspace2/html　# 0 番目はカレントディレクトリ
1 ~/workspace1/html　# 移動前直前のディレクトリが積まれる
$ pushd ../../workspace1/js
$ dirs
0 ~/workspace1/js　# 0 番目はカレントディレクトリ
1 ~/workspace2/html　# 移動前直前のディレクトリが積まれる
2 ~/workspace1/html　# 古くなるごとに下に下がる
$ pushd　# 移動先を指定しないと
0 ~/workspace2/html　# 直前にいたディレクトリに移動する
1 ~/workspace1/js　# pushd 直前のディレクトリが積まれる
2 ~/workspace1/html
```

`pushd` で移動すると移動前のディレクトリをスタックに保存して移動するので、もう一度戻る際にはパスを指定せずに `pushd` を実行すれば戻ることができます。`dirs` でスタックを確認したときの 0 番目がカレントディレクトリ、1 番目に直前にいたディレクトリ、2 番目はさらにその前にいたディレクトリ、それ以降も同様に、古くなるごとに後ろに積まれていきます。

カレントディレクトリ(0 番目)から直前にいたディレクトリ(1 番目)に移動するには `pushd` 単体で良いのですが、2 つ前にいたディレクトリ(2 番目)に移動したい場合は `pushd +2` とします。`pushd +(番号)` と入力することで `dirs` で確認した際の番号のディレクトリに飛ぶことができます。つまり、`pushd` 単体は `pushd +1` と同じということですね！

# 要らなくなったパスは popd で削除！
ディレクトリスタックが以下の状態だったとします。

```
0 ~/workspace2/html
1 ~/workspace1/js
2 ~/workspace1/html
```
ここで、workspace2/html 内のコードはすべて書き終えたので、もうこのディレクトリに来ることはなくなったとします。このままだと workspace2/html のパスがスタックに積まれたままなので、移動するときの候補が多くなり、どこに移動すればいいのかがわかりにくくなってしまいます。

既に作業を終えて、来ることがなくなったディレクトリは `popd` で削除します。単に `popd` だけで実行するとカレントディレクトリ(0 番目)がスタックから削除されます。カレントディレクトリがスタックから削除されるので、`popd` を実行すると自動的に 1 番目のパス(workspace1/js)に移動することに注意してください。

```
$ popd
$ dirs
0 ~/workspace1/js　# popd によって自動的に workspace1/js に移動することに注意！
1 ~/workspace1/html
```

```
0 ~/workspace2/html
1 ~/workspace1/js
2 ~/workspace1/html
```
`popd` 単体だと 0 番目の workspace2/html が削除されましたが、0 番目ではなく 1 番目を削除したい場合は `popd +1`、2 番目を削除したい場合は `popd +2` で削除できます。

# スタックに保存せずに移動したい場合
しかし時には、ディレクトリスタックに保存するほど頻繁にアクセスしないようなディレクトリに移動したい場合もあります。そのときは `cd` で移動します。ただし `cd` だと移動前のカレントディレクトリのパスを上書きしてしまうので、移動前のカレントディレクトリのパスを保持したまま、スタックに保存したくないディレクトリに移動したい場合は以下のようにします。

```
$ dirs
0 ~/workspace2/html
1 ~/workspace1/js
2 ~/workspace1/html
$ pushd .
0 ~/workspace2/html
1 ~/workspace2/html　# 同じパスがコピーされる
2 ~/workspace1/js
3 ~/workspace1/html
$ cd temp　# スタックに保存したくないディレクトリに移動
$ dirs
0 ~/workspace2/html/temp　# ここから 1 番目に戻るときは popd すればスタックから削除される
1 ~/workspace2/html　# ここは残った状態
2 ~/workspace1/js
3 ~/workspace1/html
```

`cd` で移動しても 0 番目はカレントディレクトリなので一時的には保存されてしまいますが、`popd` すればスタックから削除しつつ、前のディレクトリに戻ることができます。

# エイリアスの設定
さて、ここまでの説明では、`dirs` を実行したときに、左に番号が表示され、各パスが 1 行ごと表示されていますが、これは実際にはオプションをつけて `dirs -v` としなければいけません。単に `dirs` と入力すると、各パスがすべて 1 行で表示されてしまう上に、番号が表示されないので、とても不便です。でも `dirs -v` と毎回入力するのも面倒くさい…そんなときはエイリアスの出番です。`.bashrc`(zsh の場合は `.zshrc`)に以下の一行を付け足します。`.bashrc`(`.zshrc`)はホームディレクトリの隠しファイルです。

```lang:.bashrc
alias dirs='dirs -v'
```
追加して保存したら .bashrc を再読込します。

`$ source ~/.bashrc`

これで、`dirs` と入力するだけで番号が表示されるようになりました！

# まとめ
- スタックを確認するには `dirs`
- スタックにパスを保存するには `pushd`
- スタックからパスを削除するには `popd`
- `pushd` 単体では、1 番目のディレクトリに移動する
- `popd` 単体では 0 番目(カレントディレクトリ)に移動する
- 2 番目のディレクトリに移動したいときには `pushd +2` (`popd` も同じ)
- スタックに保存したくないときは `cd` で移動する
- `dirs` はエイリアスを設定すると便利