Bashシェルスクリプトファイルの絶対パスを取得

シェルスクリプト(Shell script、bash shell)を実行すると、スクリプトファイルのパスを知っておくべきことがあります。 Linuxのシェルの実行場所と関連せずにシェルスクリプトファイルの絶対パスを取得する方法について説明します。 シェルで shコマンドで直接スクリプトを実行する場合があり、sourceコマンドで環境変数が、読んでてくる場合があります。 二つのケースについて、他の方法を適用して、絶対パスを獲得しました。

この記事のコードは、Ubuntuの18.04で確認しました。

スクリプトを実行するシェルのパスを取得

シェルで pwd -Pコマンドを使用すると、現在のシェルの絶対パスを知ることができます。 これスクリプトに適用してみると、以下のように使用することができます。 `コマンド`のようにコマンドの両方に`を書いてくれればコマンドの結果が変数に代入されるということを意味します。

#!/bin/sh
SHELL_PATH=`pwd -P`
echo $SHELL_PATH

したがって、上記のスクリプトを実行してみると、以下のようにスクリプトを実行するシェルのパスを出力します。

~$ pwd
/home/js

~$ ls test/myscript.sh
test/myscript.sh

~$ sh ./test/myscript.sh
/home/js

/test$ sh ./myscript.sh
/home/js/test

最終的にはこの方法でシェルスクリプトファイルの絶対パスを取得することができません。スクリプトを実行するシェルの位置によって結果が異なります。

スクリプトを実行すると、スクリプトファイルのパスを取得

上記のコードを応用すると、スクリプトファイルの絶対パスを取得することができます。 スクリプトを実行するときにコマンドを引数として受け取るのです、その引数のパスを解析して、ファイルの場所を求めることです。 以下のように実装することができます。

#!/bin/sh
echo 'PARAM:' $0
RELATIVE_DIR=`dirname "$0"`
echo 'Dir:' $RELATIVE_DIR

cd $RELATIVE_DIR
SHELL_PATH=`pwd -P`
echo $SHELL_PATH

$0はコマンドの最初の引数を意味します。例えば sh ./myscript.sh abcというコマンドがある場合 $0./myscript.sh$1abcを意味します。

dirnameは、文字列では、ディレクトリのみを抽出してくれるコマンドです。 dirname ./myscript.sh./を返します。ファイルの相対パスを取得し、シェルがその位置に移動し、 pwdコマンドで絶対パスを取得するスクリプトファイルの絶対パスを取得することができます。

結果は以下の通りです。

~/test$ sh myscript.sh
PARAM: myscript.sh
Dir: .
Script Dir: /home/js/test

~$ sh test/myscript.sh
PARAM: test/myscript.sh
Dir: test
Script Dir: /home/js/test

まとめると、上記のコードを一行でこのように表現することができます。

DIR="$( cd "$( dirname "$0" )" && pwd -P )"
echo $DIR

readlinkにファイルのパスを取得

readlinkを利用して、上記と同じ結果を得ることができます。

readlinkは以下のようにcanonical file nameを得るに使用されるcommandです。

NAME
       readlink - print resolved symbolic links or canonical file names
DESCRIPTION
       Note realpath(1) is the preferred command to use for canonicalization functionality.
       Print value of a symbolic link or canonical file name

       -f, --canonicalize
              canonicalize by following every symlink in every component of the given name recursively; all but the last component must exist

以下は、 readlinkを使用して、上記と同じ結果を出力するコードです。

#!/bin/sh
echo 'PARAM:' $0
RELATIVE_DIR=`dirname "$0"`
echo 'Dir:' $RELATIVE_DIR

CANONICAL_DIR=`readlink -f $RELATIVE_DIR`
echo 'CANONICAL DIR:' $CANONICAL_DIR

結果

~/test$ sh myscript.sh
PARAM: myscript.sh
Dir: .
CANONICAL DIR: /home/js/test

~$ sh test/myscript.sh
PARAM: test/myscript.sh
Dir: test
CANONICAL DIR: /home/js/test

スクリプトをSourceするとき、スクリプトファイルのパスを取得

上で作成し、スクリプトを sourceコマンドで実行すると、動作しません。 $0は引数を返していないからです。 sourceを使用するときは$0の代わりに $BASH_SOURCEを使用します。

#!/bin/sh
echo 'PARAM:' $BASH_SOURCE
RELATIVE_DIR=`dirname "$BASH_SOURCE"`
echo 'Dir:' $RELATIVE_DIR

cd $RELATIVE_DIR
SHELL_PATH=`pwd -P`
echo 'Script Dir:' $SHELL_PATH

上記のスクリプトを sourceで実行すると、以下のように出力がされます。

~$ source test/myscript.sh
PARAM: test/myscript.sh
Dir: test
Script Dir: /home/js/test

まとめると、上記のコードを一行でこのように表現することができます。

DIR="$( cd "$( dirname "$BASH_SOURCE" )" && pwd -P )"
echo $DIR

readlinkにファイルのパスを取得

以下は、 readlinkを利用して、上記と同じ結果を出力するコードです。

#!/bin/sh
echo 'PARAM:' $BASH_SOURCE
RELATIVE_DIR=`dirname "$BASH_SOURCE"`
echo 'Dir:' $RELATIVE_DIR

CANONICAL_DIR=`readlink -f $RELATIVE_DIR`
echo 'CANONICAL DIR:' $CANONICAL_DIR

結果

~/test$ source myscript.sh
PARAM: myscript.sh
Dir: .
CANONICAL DIR: /home/js/test

~$ source test/myscript.sh
PARAM: test/myscript.sh
Dir: test
CANONICAL DIR: /home/js/test

まとめ

上記の方法は、私のシェルスクリプトを作成するときに、スクリプトファイルの絶対パスを取得するために使用した方法です。 このほか、他のいろいろな方法があります。参考ください。

codechachaCopyright ©2019 codechacha