bash/zshでsourceされたスクリプト内で、ファイル自身の絶対パスをとるシンプルな記法

  • 218
    いいね
  • 7
    コメント
この記事は最終更新日から1年以上が経過しています。
追記: コメント欄にて、若干変なパスが含まれている場合の対処方法について、補足いただきました。
ご指摘ありがとございますm(_ _)m

bash / zshなどでシェルスクリプトを書いていると、環境変数の設定を外部ファイルにまとめてsource して使う、というのはよくある。
そのような場合にsourceされたファイル内での絶対パスがイマイチうまく取れない、という問題に突き当たる事がある。

bashの話: うまくいかない方法と理由

通常、シェルスクリプト内で自分自身の絶対パスをとるときによくやるのが下記の手法だとおもう。

script_dir=$(cd $(dirname $0); pwd)

が、単体で呼び出した場合にはちゃんと動くのだが、bashからsourceで呼び出した場合にはうまく動かない。

なぜかというと、sourceされたファイルの実行が、呼び出し元のシェルプロセス内になるから。
bashでは$0は実行コンテキストに依らず、実行ファイル名が入っている。
そのため、source されたファイル内では$0が大本のファイルの情報となっているため、直感と異なる動きとなってしまう。

zshの話

ちなみに、zshだとちゃんと動く。zshは、$0をコンテキストに合わせて置き換える。
関数内であれば関数名になるし、sourceすればsourceされたファイルパスが入る。
そのため、zshなら$0を使っていれば問題ない。

bashの話: 解決の糸口

一般に言われるのは、$BASH_SOURCEを使う方法。
これには、呼び出されたファイル自身の絶対パスが入っている。そのため、bash限定であればこれを利用して

script_dir=$(cd $(dirname $BASH_SOURCE); pwd)

を使えば、解決できる。

これ使うと何が辛いか

bash限定なんですよね。zshかbashかを判定して、場合分けするような処理をいちいち書きたくない。

じゃあどうすんの

こうすればいい

script_dir=$(cd $(dirname ${BASH_SOURCE:-$0}); pwd)

$BASH_SOURCEが定義されていればそれを使い、無いなら$0を使う。
これでさくっと解決できる。

最後のほう書くの面倒になって説明が雑になった。。。わけじゃないよ!><