シェルスクリプト (bashスクリプト、zshスクリプト等) を書いた時、 そのファイルの絶対パス を取得するケースはよくあります。
例えば、そのシェルスクリプトから設定ファイルを読み込みたい場合などによく使います。
例えば、このようなスクリプトが scripts ディレクトリの中に run.sh という名前で作ってあって、
scripts/run.sh
#!/usr/bin/env zsh
. ./env.sh
(なにか処理...)
これを、
cd scripts
./run.sh
としても動作させる必要があり、 cd scripts しなくても
./scripts/run.sh
としても動作させたいのは、よくある要件でしょう。
その場合、定番として
scripts/run.sh
#!/usr/bin/env zsh
cd "$(dirname $0)" || exit
. ./env.sh
(なにか処理...)
$(dirname $0)
と書きます。大抵はこれで十分なのですが、もしドットコマンドで読み込む設定ファイル env.sh の中でも同じことをやりたくて
scripts/env.sh
#!/usr/bin/env zsh
cd "$(dirname $0)" || exit
credentials_path=$(pwd)/credentials
とか
scripts/env.sh
#!/usr/bin/env zsh
credentials_path=$(dirname $0)/credentials
とやってしまうと、特定の状況でうまくいきません。
使用者は、
cd scripts
./run.sh
とか
./scripts/run.sh
とする以外にも、設定ファイルだけ読み込みたくて、他のディレクトリにあるファイルから
. ../scripts/env.sh
のように、設定ファイルを適用してしまう場合もあるためです。
検証
以下のファイルを作り、検証してみます。
scripts/run.sh
#!/usr/bin/env zsh
cd "$(dirname $0)" || exit
. ./env.sh
scripts/env.sh
#!/usr/bin/env zsh
echo "arg0: $0"
echo "PWD: $PWD"
cd scripts/; ./run.sh の場合
% ./run.sh
arg0: ./env.sh
PWD: /Users/ytyng/my-project/scripts
./scripts/run.sh の場合
% ./scripts/run.sh
arg0: ./env.sh
PWD: /Users/ytyng/my-project/scripts
上記2つはどちらも期待通りですが
./scripts/env.sh の場合
% ./scripts/run.sh
arg0: ./env.sh
PWD: /Users/ytyng/my-project/scripts
上記2つはどちらも期待通りですが
. ./scripts/env.sh
% . ./scripts/env.sh
arg0: ./scripts/env.sh
PWD: /Users/ytyng/my-project
env.sh を、他のディレクトリからドットコマンドで適用した場合、 $0
などの結果が最初の例と変わってしまいます。
シェルスクリプトの中で安定して現在のディレクトリを取得するには
scripts/env.sh
#!/usr/bin/env zsh
cd $(dirname $0) 2>/dev/null || cd ${PWD}
env_pwd=$(pwd)
cd -
少し強引ですが、上記のように dirname $0
が失敗したら ${PWD}
に cd
すればうまくいくと思います。
応用
スクリプトのあるディレクトリの2つ上の /credentials ディレクトリを作る
cd $(dirname $0) 2>/dev/null || cd $PWD
credentials_dir=$(dirname $(dirname $(pwd)))/credentials
cd -