やりたいこと
例えば~/v1.0.0、~/v2.0.0…みたいに何らかのプログラムとか プロジェクトをバージョン毎に管理してたりするとき、 その中にsetup.shみたいなのを置いておいて、そのファイルの中で、
export PATH=~/v1.0.0/bin:$PATH
export LD_LIBRARY_PATH=~/v1.0.0/lib:$LD_LIBRARY_PATH
みたいな設定をしたいとします。
この様に直接PATHを書いてしまうと、新しいバージョンになった時に この設定ファイル自体も書き換えが必要です。
また、違う環境に持っていった時にPATHが変わってしまう可能性があります。
なので、通常は、この様な設定ファイルの中では
export PATH=$PROJECT_PATH/bin:$PATH
export LD_LIBRARY_PATH=$PROJECT_PATH/lib:$LD_LIBRARY_PATH
みたいにして、PROJECT_PATHの様な別の環境変数を参照するようにして、
実際sourceする際に、
$ export PROJECT_PATH=~/v1.0.0
$ source ~/v1.0.0/setup.sh
みたいにする方が素直に出来ます。
ですが、これだと1回余計な設定が必要になってしまいます。
source ~/v1.0.0/setup.shの時点でそのディレクトリを見てるわけなので
ファイルのなかで自動で自分のパスを取得して設定してほしいな、と。
BASH_SOURCE
以下、Bash 4.3.33でやっています。
Bashの通常のスクリプトだと、引数の0番目、$0、にファイルへのパスが入っています。
1 2 | |
これを実行すると(直接、またはbashの引数として):
$ ./path.sh
./path.sh
$ bash ./path.sh
./path.sh
$ mkdir test && cd test
$ ../path.sh
../path.sh
$ cd ../
ただ、source(または.)すると
$ source path.sh
/usr/local/bin/bash
と、現在使ってるシェルが$0に入っています。
これは
$ echo $0
/usr/local/bin/bash
となるように、現在のbashのセッションの中でそのままコマンドが実行されてる
のと同じだとみなされるからです。
この様な場合は代わりにBASH_SOURCEというシェル変数があって、
ここにsourceで呼び出されたファイルのパスが入っています。
1 2 3 | |
とすると、
$ ./path2.sh
./path2.sh
./path2.sh
$ source ./path2.sh
/usr/local/bin/bash
./path2.sh
$ cd test
$ ../path2.sh
../path2.sh
../path2.sh
$ source ../path2.sh
/usr/local/bin/bash
../path2.sh
と言った感じにBASH_SOURCEの方ではsourceした場合でもファイルのパスを取ってこれます。
これを使えば後は、
1 2 3 | |
とでもしておけばOK。
"$(cd "$(dirname "$BASH_SOURCE")" && pwd)"
の部分はdirnameでファイルのあるディレクトリを取得、
その後一旦そのディレクトリに移動してpwdをすることで
ファイルのあるディレクトリへの絶対パスを取得しています。
これでどこからsource ~/v1.0.0/setup.shをしても
PATHの値が
~/v1.0.0/bin:$PATH
になります。
また、同じファイルを~/v2.0.0/setup.shにおいておけば、
source ~/v2.0.0/setup.shをした場合、
~/v2.0.0/bin:$PATH
が設定されます。
Zshでは
使ったZshは5.0.5。
Zshではsourceをした場合は
${(%):-%N}が${BASH_SOURCE}と同じ役割をします1。
1 2 3 | |
この様なスクリプトを作ってみると
$ ./path3.sh
./path3.sh
./path3.sh
$ source ./path3.sh
./path3.sh
./path3.sh
となり、この場合$0でもsourceで取ってこれてる様に見えます。
ただし、これはオプションによっては使えない場合があって、
setopt nofunction_argzero
または
unsetopt function_argzero
の設定をしていると
$ setopt nofunction_argzero
$ ./path3.sh
./path3.sh
./path3.sh
$ source ./path3.sh
zsh
./path3.sh
と、sourceした時にはzshという値が入ってしまいます。
${(%):-%N}の方はファイルへのパスのまま。
同じ様なことが.zshrcで設定した時にもオプションに関係なく起こります。
なので$0ではなく${(%):-%N}を使います。
従って、Zsh用のセットアップファイルであるならば
1 2 3 | |
の様にしておけばOK。
Bash/Zsh両用
もし、Bash/Zsh両方で使いたければ
1 2 3 4 5 6 7 | |
のようにわけるか、まとめて
1 2 3 | |
の様に、BASH_SOURCEを探して、無ければZsh用の変数を検索、
みたいにすることも出来ます。
-
man zshmiscを見ると%NはThe name of the script, sourced file, or shell function that zsh is currently executing, whichever was started most recently. If there is none, this is equivalent to the parameter $0. An inte- ger may follow the `%’ to specify a number of trailing path com- ponents to show; zero means the full path. A negative integer specifies leading components.
とのこと。
