BASHで__FILE__や__DIR__みたいなもの

シェルスクリプト(BASH限定ですが)、他の言語でもよく見られる__FILE__や__DIR__みたいなことをするにはどのようにすれば良いか、と考えてみた結果以下のようになった。小生のシェルスクリプトスキルが高くないので何ともだが上手く動いているようだ。もっと良いやり方があるかもしれない。クロスシェル対応できたらと思ったが、他のシェルスクリプトのスキルがほぼないので今後の課題とする。。

set -ue

__FILE__() {
  resolve_link "${BASH_SOURCE[1]}"
}

__DIR__() {
  dirname "$(resolve_link "${BASH_SOURCE[1]}")" # 間違い 9/30 修正
}

resolve_link() {
  local filepath="$1"
  local filename
  (
    while [ "$filepath" != "" ]; do
      cd "$(dirname "$filepath")"
      filename="$(basename "$filepath")"
      filepath="$(readlink "$filename" ||:)"
    done
    echo "$(pwd -P)/$filename"
  )
}

それぞれのsource先でBASH_SOURCE変数を参照する方法でも良いが、シンボリックリンクの場合に絶対パスを取得できないので、一枚関数をかましている。resolve_linkの方法は参考リンクを参照させていただいた。readlink-fオプションが使えない場合でも動く。

以下のようなファイル構成で試してみる。環境はMax OS X。

$ tree
.
├── bar -> foo.sh
├── file.sh
├── foo.sh
├── hello -> hello.sh
└── hello.sh

0 directories, 5 files
$ pwd
/tmp/sample

foo.sh

#!/usr/bin/env bash
source file.sh

echo $BASH_SOURCE
__FILE__
__DIR__
dirname "`__FILE__`"

source hello

hello.sh

#!/usr/bin/env bash
echo "*** hello.sh ***"
echo $BASH_SOURCE
__FILE__

barの実行。__FILE__でちゃんとbarの参照先foo.shの絶対パスが表示されているようだ。

$ ./bar
./bar
/private/tmp/sample/foo.sh
/private/tmp/sample
/private/tmp/sample
*** hello.sh ***
hello
/private/tmp/sample/hello.sh

foo.shの実行。

$ ./foo.sh
./foo.sh
/private/tmp/sample/foo.sh
/private/tmp/sample
/private/tmp/sample
*** hello.sh ***
hello
/private/tmp/sample/hello.sh

参考リンク

  • http://qiita.com/yudoufu/items/48cb6fb71e5b498b2532
  • http://qiita.com/edvakf@github/items/b8400f7dfe9210aadddd

byebyehaikikyou

日記やIT系関連のネタ、WordPressに関することなど様々な事柄を書き付けた雑記です。ITエンジニア経験があるのでプログラミングに関することなどが多いです。

シェアする

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

コメントする

Translate »