シェルスクリプト(Bash)でcdができない

ディレクトリを作成し、同時にそのディレクトリに移動するシェルスクリプトを書きたかった。

要約

#!/bin/bash
# mkcd.sh
mkdir $1
cd $1

のように書いて、

$ ./mkcd.sh hoge

のように呼び出すと、「hoge」ディレクトリは作成されますが、肝心の移動ができません。

これを防ぐには、

$ . ./mkcd.sh hoge

のように、ドット(と空白)を入れてあげる必要があります。

理由

シェルスクリプトは、基本的に、現在のシェルとは別のシェル(サブシェル)で実行されます。

そのため、サブシェルでいくらディレクトリを移動しても、スクリプトが終了すると、もともといたディレクトリに戻されてしまいます。

補足

上のスクリプトで「cd $1」の後に「touch a.txt」とすると、きちんとhogeディレクトリ内部にa.txtが生成されます。それぞれのシェルが「現在のディレクトリ」を保持しているようです。

しかし、「. 」(ドット)コマンドを使うと、スクリプトが現在のプロセスで実行されます。

「. 」を付けることで、スクリプト内部で実行したcdが、現在のシェルに反映されるのです。

ちなみに、この「.」を、「source」にしても、同じ意味になります。

別の解決法

毎回コマンドを呼び出すときに「. 」と入力するのば面倒な場合は、関数を使うと良いらしいです。

# ~/.bashrc または ~/.bash_profile
mkcd() {
  mkdir $1
  cd $1
}

~/.bashrc のような場所に書かれた関数は、ターミナルを開くと自動で読み込まれます。

ただ、~/.bashrcを編集した場合は、

$ source ~/.bashrc

のように再読み込みしましょう(~/.bash_profileも同様)。でないと関数が有効になりません。

まとめ

……関数のほうが圧倒的に楽ですね。

シェルスクリプトの中でcdが使えないという情報が全然なかったのはこれが原因だったのか。

余談ですが、この問題でずっと悩んで1時間以上溶かしました。つらい。

参考

Stack Overflow

Avatar
fiore

自称C++er。

comments powered by Disqus