コード型ログ(5) Bashで自分のディレクトリを知る

シェルスクリプトで自分のディレクトリを知りたいことがあります。

. ./functions.sh

例えば、上のように他のシェルスクリプトを読み込みたいときに相対パスを使うのはよくないときがあります。なぜならば、./の場所はシェルスクリプトを実行するカレントディレクトリであって、シェルスクリプトのファイルがある場所ではないからです。シェルスクリプトは、どのディレクトリから実行しても動くようにしたいものです。

シェルスクリプトのファイルが存在するディレクトリを知るには以下のようにします。

MYNAME="${BASH_SOURCE:-$0}"
MYDIR=$(cd -P -- $(dirname -- "${MYNAME}"); pwd)

${MYNAME}には今のファイルの相対パスが入っています。

${BASH_SOURCE:-$0}となっているのは、$0にはBash以外では今のファイルの名が入るのですが、Bashだとsourceもしくは.でファイルを呼んだ実行ファイルの名前が入るからです。Bashには今のファイル名を表す変数BASH_SOURCEというのが定義されているので、BASH_SOURCEが定義されている場合にはそれを使い、BASH_SOURCEが定義されていない、つまりBash以外のシェルの場合は$0を使います。

"${A:-a}"というのは変数Aが定義されているときは${A}を返し、そうでないときはaを返すという意味です。なお、:-のセミコロンは省略して${A-a}でも可能です。*1

${MYDIR}には今のファイルのディレクトリの絶対パスが入っています。

dirname -- "${MYNAME}ディレクトリ名を取得します。--はファイル名が-で始まっているような場合にコマンドラインオプションとしてみなされないようにするためです。慣例として--以降の引数はオプションとしてみなされません。

しかし、このままでは相対パスかもしれません。なので、絶対パスが欲しいときには、$(cd -P -- ${RELATIVE_DIR}; pwd)として、絶対パスに変化します。-P${RELATIVE_DIR}シンボリックリンクが含まれていたときにそれを解くオプションです。

. ${MYDIR}/functions.sh

とすれば、どこから実行ファイルを呼んでもfunctions.shを見つけることができます。


追記

上では、実行ファイルがシンボリックリンクとなっている場合は、実体のあるディレクトリは分からない。その場合には、

MYNAME=$(readlink -f "${BASH_SOURCE:-$0}")

とする。

*1:ややこしいので個人的には"${A:-a}"で統一してほしいです。