課題
次のような外部ファイルに依存するシェルスクリプトは、
cronによって絶対パスで実行されたときと、手元で実行したときとでは
実行場所が異なるため、うまく動かないケースがある。
main.sh
#!/bin/bash
./hello.sh
# main.shとhello.shは同じディレクトリに存在する
$ ls
hello.sh main.sh
# main.shを実行すると成功する
$ bash main.sh
hello
# 一つ上のディレクトリに移動する
$ cd ..
# dirディレクトリの中に、main.sh, hello.shが入っている
$ ls
dir
# ここでmain.shを実行すると、今のディレクトリに「hello.sh」が存在しないので怒られる
$ bash dir/main.sh
dir/main.sh: line 3: ./hello.sh: No such file or directory
解決策
これを解決するためには、
シェルスクリプトが処理を実行する前に
自分が置かれているディレクトリに移動してから処理を開始する
というふうに考えれば良い。
そのため
cd "$(dirname "$0")"
を記述することでこれを回避できる。
dirname
:フルパスが与えられた際に、ディレクトリ部分を取り出す$0
:シェルが実行された時のコマンド自身$()
:コマンドの出力をそのままスクリプト中で利用する
つまり、bash dir/main.sh
と実行された場合、このコマンドは下記のように展開される。
cd dir
結果
main.sh
#!/bin/bash
cd "$(dirname "$0")"
./hello.sh
実行
# 上の階層のディレクトリで実行
$ bash dir/main.sh
hello
# ディレクトリ移動
$ cd dir
# 先ほどとは違うディレクトリから実行
$ ls
hello.sh main.sh
$ bash main.sh
hello
まとめ
- 実行時のパス指定から、シェルスクリプトが置かれている場所を取得
- その場所までcdコマンドで移動
- ここからは行いたい処理を実行する
という考え方で実現できる。