1. 概要

多くの場合、スクリプト自体からスクリプトのファイル名を見つける必要があります。 一般的な使用例の1つは、 –helpオプションを使用してスクリプトの使用法を示すことです。

このチュートリアルでは、bashでこれを実現するいくつかの方法について説明します。

2. basenameコマンドの使用

basename コマンドを使用すると、ファイル名からディレクトリとサフィックスを削除できます。 これを使用して、スクリプトのファイル名を見つけることができます。

$ cat dir1/dir2/find-script-name.sh 
#!/bin/bash
echo "Script name =" $(basename "$0")

$ dir1/dir2/find-script-name.sh 
Script name = find-script-name.sh

この例では、 $0コマンドとbasenameコマンドを組み合わせて使用して、呼び出したスクリプトのファイル名を検索しています。 $ 0 は、ファイル名を相対パスで表すbashの特別な変数です。 したがって、 basename コマンドを使用して、スクリプトのファイル名からディレクトリ名を削除しました。

3. パラメータ拡張の使用

bash パラメーター展開を使用して、スクリプトのファイル名を見つけることもできます。

$ cat dir1/dir2/find-script-name.sh 
#!/bin/bash
echo "Script name = ${0##*/}"

$ dir1/dir2/find-script-name.sh 
Script name = find-script-name.sh

この例では、 $ {0 ## */}はパラメーター展開を表します。

4. BASH_SOURCE環境変数の使用

BASH_SOURCE は、ファイル名を含むbashの環境変数です。 basename コマンドで使用して、スクリプトのファイル名を取得できます。

$ cat dir1/dir2/find-script-name.sh 
#!/bin/bash
echo "Script name =" $(basename "${BASH_SOURCE}")

$ /dir1/dir2/find-script-name.sh 
Script name = find-script-name.sh

5. リンクを介してスクリプトを呼び出すときの問題

Linuxでは、ファイルを別の場所にリンクすることは、特に実行可能ファイルの場合、一般的な操作です。 これまで、例を通じて、スクリプト自体からスクリプトのファイル名を見つける3つの方法を学びました。

次に、シンボリックリンクを介してスクリプトを呼び出しても機能するかどうかを確認しましょう。

まず、3つのアプローチを含む新しいスクリプトを作成しましょう。

$ cat dir1/dir2/find-script-name-all.sh
#!/bin/bash
echo 'Getting name by basename $0: ' $(basename "$0")
echo 'Getting name by ${0##*/}: ' ${0##*/}
echo 'Getting name by basename ${BASH_SOURCE}: ' $(basename "${BASH_SOURCE}")

次に、スクリプトへのシンボリックリンクを作成し、リンクによってスクリプトを呼び出します。

$ ln -s dir1/dir2/find-script-name-all.sh i-am-a-link
$ ls -l i-am-a-link 
lrwxrwxrwx 1 kent kent 33 Jan 24 23:10 i-am-a-link -> dir1/dir2/find-script-name-all.sh

$ ./i-am-a-link 
Getting name by basename $0:  i-am-a-link
Getting name by ${0##*/}:  i-am-a-link
Getting name by basename ${BASH_SOURCE}:  i-am-a-link

上記の出力からわかるように、 3つのアプローチすべてで、実際のスクリプト名ではなくリンクの名前が報告されています。 つまり、すべてのアプローチが失敗しました。

次に、この問題を解決する方法を見てみましょう。

6. readlinkコマンドの使用

readlink コマンドを使用して、この問題を解決できます。 find-script-name-all.shスクリプトに2つの新しいコマンドを追加しましょう。

$ cat dir1/dir2/find-script-name-all.sh 
#!/bin/bash
echo 'Getting name by basename $0: ' $(basename "$0")
echo 'Getting name by ${0##*/}: ' ${0##*/}
echo 'Getting name by basename ${BASH_SOURCE}: ' $(basename "${BASH_SOURCE}")
echo '------ Using readlink ----- '
echo 'Getting name by basename $(readlink -f ${BASH_SOURCE}): ' $(basename "$(readlink -f "${BASH_SOURCE}")")
echo 'Getting name by basename $(readlink -f $0): ' $(basename "$(readlink -f "$0")")

ここでは、 -fオプションを指定したreadlinkコマンドを使用して、すべてのシンボリックリンクを再帰的に追跡しています

次に、リンクを使用してスクリプトを再度呼び出し、実際のスクリプトファイル名を取得できるかどうかを確認します。

$ ./i-am-a-link 
Getting name by basename $0:  i-am-a-link
Getting name by ${0##*/}:  i-am-a-link
Getting name by basename ${BASH_SOURCE}:  i-am-a-link
------ Using readlink ----- 
Getting name by basename $(readlink -f ${BASH_SOURCE}):  find-script-name-all.sh
Getting name by basename $(readlink -f $0):  find-script-name-all.sh

上記のテストが示すように、 readlink を使用した新しいコマンドは、スクリプトの実際のファイル名を報告できます。

さらに、スクリプトを直接呼び出すと、readlinkアプローチも機能することに注意してください。

$ dir1/dir2/find-script-name-all.sh 
Getting name by basename $0:  find-script-name-all.sh
Getting name by ${0##*/}:  find-script-name-all.sh
Getting name by basename ${BASH_SOURCE}:  find-script-name-all.sh
------ Using readlink ----- 
Getting name by basename $(readlink -f ${BASH_SOURCE}):  find-script-name-all.sh
Getting name by basename $(readlink -f $0):  find-script-name-all.sh

したがって、readlinkアプローチは問題の一般的な解決策です。

7. 結論

この記事では、スクリプト自体の中からスクリプトのファイル名を取得するための実用的な方法のいくつかについて説明しました。

さらに、スクリプトがシンボリックリンクを介して実行されるシナリオについても説明しました。