オープンソースこねこね

Webプログラミングなどについてあれこれ。

Bashスクリプトで実行ファイルのディレクトリを取得する

よくやるのが以下の記述だったのだけれど

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

これだと、このスクリプトシンボリックリンクから呼び出したときに、 実ファイルのパスでなくリンク先のディレクトリが取得されてしまっていた。 シンボリックリンクから呼び出されたときも、実ファイルのパスを返すようにするには、

SCRIPT_DIR=$(cd $(dirname $(readlink $0 || echo $0));pwd)

のようにすればよさげ。

追記)id:ngyukiさんにご指摘をいただいたので修正。

スクリプトシンボリックリンクなディレクトリにあることを考慮して readlink -f とか cd -P とか pwd -P とかにするとなお良いのかな

おお、なるほど。やってみたら確かにシンボリックリンクなディレクトリにあるとうまくいかなかった。なので修正した以下の書き方がベターです。

SCRIPT_DIR=$(cd $(dirname $(readlink -f $0 || echo $0));pwd -P) 

これならうまくいきました。

追記)2014-06-25

上記の記事はシンボリックリンク相対パスだとやっぱりうまくいかなかったり、readlink -fmacでは使えなかったりでいろいろ至らない。 その後もいろいろ調べたら、rbenvスクリプト内にあったabs_dirnameがいい感じでした。 ちょこっと手直ししたのが以下になります。

abs_dirname() {
  local cwd="$(pwd)"
  local path="$1"

  while [ -n "$path" ]; do
    cd "${path%/*}"
    local name="${path##*/}"
    path="$(readlink "$name" || true)"
  done

  pwd -P
  cd "$cwd"
}

script_dir="$(abs_dirname "$0")"