結論
"$(cd "$(dirname "$(realpath "${BASH_SOURCE:-0}")")"; pwd)"
自身がシンボリックリンクのとき元パスをたどらず、シンボリックリンクファイル自体のパスにしたいなら以下。
"$(cd "$(dirname "${BASH_SOURCE:-$0}")"; pwd)"
類似
使いどころ
自分自身をルートとした相対パスにより、別のスクリプトファイルを参照する。
- /tmp/
- repo/
- main.sh
- sub.sh
 
 
- repo/
main.sh
. "$(cd "$(dirname "${BASH_SOURCE:-$0}")"; pwd)/sub.sh"
 main.shからsub.shを参照する。相対パスのルートは/tmp/repoである。
 カレントディレクトリを/home/piなど全く別のパスにしても相対パスのルートは変わらず/tmp/repoである。
cd /home/pi
/tmp/repo/main.sh
 もし$0だと相対パスのルートは/home/piになってしまう。よって冒頭にある通り$BASH_SOURCEが必要。
回避した罠
$0は呼出元パスになってしまう
 検証コードを書く。a.shファイルで期待するのはa.shファイルのフルパスである。
cd /tmp/work
a.sh
echo "\$0: $0" echo "\$BASH_SOURCE: $BASH_SOURCE"
b.sh
. a.sh
chmod 755 a.sh chmod 755 b.sh
実行する。
./b.sh
$0: ./b.sh $BASH_SOURCE: /tmp/work/a.sh
 期待値a.shのフルパスを取得できたのは$BASH_SOURCEだけ。$0は呼出元のb.shパスとなってしまった。しかも相対パスであり絶対パスでない。
cd ~
/tmp/work/b.sh
$0: /tmp/work/b.sh $BASH_SOURCE: /tmp/work/a.sh
 $0には以下2点の問題があることが判明した。
 どんなときでも$0で絶対パスが欲しいときは以下のようにする。
$(cd $(dirname $0); pwd)
クォートすべきである
 さもなくばエラーになりうる。エラーになるのはファイルパスにスペースが入っているのにクォートされていないときだ。
スペースはbashのメタ文字である。もしスペースがあるのにクォートされていなければ、別コマンド・別引数として扱われてエラーになってしまう。それを防ぐためクォートする。
"$(cd "$(dirname "$0")"; pwd)"
クォートはダブルクォートのみ有効。シングルクォートだと展開できずリテラル値になってしまうため。
 pwd -Pのように-Pオプションを付与することでシンボリックリンクを物理パスへと解決できる。
対象環境
- Raspbierry pi 4 Model B
- Raspbian buster 10.0 2019-09-26 ※
- bash 5.0.3(1)-release
$ uname -a Linux raspberrypi 4.19.75-v7l+ #1270 SMP Tue Sep 24 18:51:41 BST 2019 armv7l GNU/Linux