【Linux】シェルスクリプトの実行場所を気にしなくて良いように、相対パスでも絶対パスでも同じ動作をさせる

Linuxコマンド シェルスクリプト

課題

次のような外部ファイルに依存するシェルスクリプトは、
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コマンドで移動
  • ここからは行いたい処理を実行する

という考え方で実現できる。

タイトルとURLをコピーしました