Bashファイルパスを取得する関数を作った(自分自身・呼出元)
API。
成果物
実行
mkdir -p /tmp/work cd /tmp/work git clone https://github.com/ytyaru/Shell.Path.20200118125311 cd /src ./test_path.sh ./call_path.sh
結果は以下。
Cleared all test. 20 SelfPath : /tmp/work/Shell.Path.20200118125311/src/path.sh SelfName : path.sh SelfExt : sh SelfNameId : path CallerPath : /tmp/work/Shell.Path.20200118125311/src/call_path.sh CallerName : call_path.sh CallerExt : sh CallerNameId: call_path
コード
#!/usr/bin/env bash SelfPath() { echo "$(__Join "$(SelfParent)" "$(SelfName)")"; } SelfParent() { echo "$(__Parent "${BASH_SOURCE:-0}")"; } SelfName() { echo "$(__Name "${BASH_SOURCE:-0}")"; } SelfExt() { echo "$(__Ext "${BASH_SOURCE:-0}")"; } SelfNameId() { echo "$(__NameId "${BASH_SOURCE:-0}")"; } # WithoutExt CallerPath() { echo "$(__Join "$(CallerParent)" "$(CallerName)")"; } CallerParent() { echo "$(__Parent "$0")"; } CallerName() { echo "$(__Name "$0")"; } CallerExt() { echo "$(__Ext "$0")"; } CallerNameId() { echo "$(__NameId "$0")"; } # WithoutExt __Join() { args=("$@"); echo "$(IFS=/; echo "${args[*]}")"; } __Parent() { echo "$(cd "$(dirname "$1")"; pwd)"; } __Name() { echo "$(basename "$1")"; } __Ext() { local n="$(__Name $1)"; echo "${n##*.}"; } __NameId() { local n="$(__Name $1)"; echo "${n%.*}"; }
問題
ライブラリをロードする時点で、ライブラリで実装した内容の一部を生で書かねばならない。
. "$(cd $(dirname ${BASH_SOURCE:-$0}); pwd)/path.sh"
本当は以下のように相対パスで書きたいが問題あり。
. ./sub/path.sh
相対パスだと参照できない場合がある。そのスクリプトを絶対パス指定でコマンド実行したとき、そのときのカレントディレクトリが相対パスのベースになってしまう。もし実行時のカレントディレクトリが、相対パスで省略したパスでなければ参照できない!
つまり、相対パスで参照するためには、実行時のカレントディレクトリが、相対パスで省略したパスであるべきである。
これは現実的でない。ふつうはカレントディレクトリに関係なく、そのファイルが存在するディレクトリパスをベースとして欲しいはず。そのように動作させるためには、先述の$BASH_SOURCE
を含むコードを書かねばならない。
この問題は次のような問題に発展する。
- モジュール化困難
- ファイル毎に冗長なコードを書かねばならない
- ファイル毎にパスを気にせねばならない
原因
原因はbash言語がimport機能を持っていないこと。以下のように言語拡張してくれないかな。
import sub/path.sh echo "$(path.SelfPath)"
対策
自分でimport
コマンドを作ればいける? それを環境変数PATH
に通せば。
import sub/path.sh echo "$(path.SelfPath)"
だが、importは呼出元の子プロセスになってしまう。子プロセスでロードした環境変数は親プロセスで使えない……。
- https://stackoverflow.com/questions/4391456/how-to-use-the-same-bash-variable-between-a-parent-shell-and-child-shell
- https://serverfault.com/questions/37796/how-to-export-vars-from-a-subshell-to-a-parent-shell
では.
(source
)で親自身の一部としてロードしたらどうか?
. import sub/path.sh echo "$(path.SelfPath)"
import
自体をimport
しているかのようなコードで違和感がある。でもこれで動くなら妥協できるか?
名前空間みたいに.
をつけることはできるのか?
関数のリネームは以下が参考になりそう。
対象環境
- 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