シェルスクリプトの中から、実行したスクリプトのあるディレクトリを必要とする場面はちょいちょいある。 たとえば、スクリプトの中で相対パスを使って別のファイルを読み込むような処理が典型的だと思う。 その場合、スクリプトを実行したときのカレントディレクトリを起点として相対パスを処理してしまうと上手くいかない。 代わりに、スクリプトのあるディレクトリを把握した上で、そこを起点に相対パスを処理する必要がある。 今回は、それを実現する方法についてメモしておく。
使った環境は次のとおり。
$ sw_vers ProductName: Mac OS X ProductVersion: 10.15.7 BuildVersion: 19H15 $ bash --version GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin19) Copyright (C) 2007 Free Software Foundation, Inc. $ dirname --version dirname (GNU coreutils) 8.32 Copyright (C) 2020 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Written by David MacKenzie and Jim Meyering.
もくじ
下準備
今回のサンプルコードは、macOS に標準で入っている BSD dirname でも動作する。 ただし、検証に使っている環境としては GNU Coreutils の実装を利用している。
$ brew install coreutils $ alias dirname="gdirname"
スクリプトのあるディレクトリを取得する
早速だけど、以下にサンプルコードを示す。
以下のサンプルコードでは SCRIPT_DIR
というシェル変数に、スクリプトのあるディレクトリを絶対パスで代入している。
#!/usr/bin/env bash set -CEuo pipefail # dirname $0 でスクリプトの存在するディレクトリが得られる # インラインコマンドで cd して pwd すれば絶対パスが得られる SCRIPT_DIR=$(cd $(dirname $0) && pwd) echo ${SCRIPT_DIR}
上記を適当な名前と場所に保存しよう。
ここでは example.sh
という名前で /tmp
ディレクトリに保存した。
まずは、試しに Bash に絶対パスでシェルスクリプトを指定して実行してみる。
$ bash /tmp/example.sh /tmp
ちゃんと保存されているディレクトリの絶対パスが表示された。
続いてはルートディレクトリに移動してから相対パスでシェルスクリプトを指定してみよう。
$ cd /
$ bash ./tmp/example.sh
/tmp
これでも、ちゃんと保存されているディレクトリの絶対パスが表示された。
ついでに、実行権限をつけて、Shebang 経由でスクリプトを実行してみよう。
$ chmod +x example.sh $ ./tmp/example.sh /tmp
これも、ちゃんと表示される。
動作原理について
あとはもう蛇足だけど、どうして先ほどのサンプルコードが動作するかの説明をしていく。
変数 $0
について
そもそも、シェルスクリプトでは $0
という変数にスクリプトが実行されたときのパスが入る。
たとえば、次のようなサンプルコードを用意してみよう。
#!/usr/bin/env bash set -CEuo pipefail # 最初の引数は実行するときに使ったパスになる echo $0
上記を、先ほどと同じように色々な呼び方で実行してみよう。
$ bash /tmp/example.sh /tmp/example.sh $ bash ./tmp/example.sh ./tmp/example.sh $ ./tmp/example.sh ./tmp/example.sh
呼び方によって絶対パスだったり相対パスだったりが入っている。
dirname(1) について
そして、dirname(1) を使うとパスの中でディレクトリの部分が得られる。 たとえば、シェルから直接呼んでみると、次のようになる。
$ dirname /tmp/example.sh /tmp $ dirname ./tmp/example.sh ./tmp
これで、ひとまずスクリプトのあるディレクトリが相対パスで得られた。 あとは、扱いやすさを考えて必要に応じて絶対パスにする。 絶対パスにするときはインラインで cd して pwd すれば良い。
$ (cd $(dirname ./tmp/example.sh) && pwd) /tmp $ (cd $(dirname /tmp/example.sh) && pwd) /tmp
いじょう。
補足
シンボリックリンクが使われている場合には、必要に応じて pwd(1) に -P
オプションを指定して解決した方が良いかも。
- 作者:もみじあめ
- 発売日: 2020/02/29
- メディア: Kindle版