最も一般的なケースで$0は、絶対パスまたはスクリプトへの相対パスが含まれるため、
script_path=$(readlink -e -- "$0")
(readlinkコマンドがあり、それがをサポートしている場合-e)は、通常、スクリプトへの正規の絶対パスを取得するのに十分な方法です。
$0 インタプリタに渡されるスクリプトを指定する引数から割り当てられます。
たとえば、次の場所にあります。
the-shell -shell-options the/script its args
$0取得しthe/scriptます。
実行すると:
the/script its args
あなたのシェルは次のことをします:
exec("the/script", ["the/script", "its", "args"])
スクリプトに#! /bin/sh -たとえばシバンが含まれている場合、システムはそれを次のように変換します。
exec("/bin/sh", ["/bin/sh" or "the/script", "-", "the/script", "its", "args"])
(シバンが含まれていない場合、またはより一般的にはシステムがENOEXECエラーを返した場合、同じことを行うシェルです)
一部のシステムではsetuid / setgidスクリプトに例外があり、システムが一部のシステムでスクリプトを開いてfd x代わりに実行します。
exec("/bin/sh", ["/bin/sh" or "the/script", "-", "/dev/fd/x", "its", "args"])
競合状態を回避するため(この場合$0はが含まれます/dev/fd/x)。
さて、あなたはそれが主張すること/dev/fd/x でそのスクリプトへのパス。ただし、から読み取る場合$0、入力を使用するときにスクリプトが壊れることに注意してください。
ここで、呼び出されたスクリプトコマンド名にスラッシュが含まれていない場合は、違いがあります。に:
the-script its args
シェルがで検索さthe-scriptれ$PATHます。$PATH一部のディレクトリへの絶対パスまたは相対パス(空の文字列を含む)を含めることができます。たとえば、現在のディレクトリに$PATH含まれ/bin:/usr/bin:、the-script見つかった場合、シェルは次のことを行います。
exec("the-script", ["the-script", "its", "args"])
これは次のようになります:
exec("/bin/sh", ["/bin/sh" or "the-script", "-", "the-script", "its", "args"]
または、次の場所にある場合/usr/bin:
exec("/usr/bin/the-script", ["the-script", "its", "args"])
exec("/bin/sh", ["/bin/sh" or "the-script" or "/usr/bin/the-script",
"-", "/usr/bin/the-script", "its", "args")
上記のすべてのケースで、setuidのコーナーケースを除き$0、スクリプトへのパス(絶対パスまたは相対パス)が含まれます。
これで、スクリプトは次のように呼び出すこともできます。
the-interpreter the-script its args
the-script上記のようにスラッシュ文字が含まれていない場合、動作はシェルごとにわずかに異なります。
古いAT&T ksh実装は実際には無条件に$PATHスクリプトを検索していたため(実際にはバグであり、setuidスクリプトのセキュリティホールでした)、$0実際に現在のディレクトリで検索が行われない限り、スクリプトへのパスは含まれていませんでした。$PATHthe-script
新しいAT&T kshはthe-script、現在のディレクトリが読み取り可能であれば、それを解釈して解釈します。そうでない場合は、で読み取り可能および実行可能ファイル を検索the-scriptし$PATHます。
の場合bash、the-script現在のディレクトリにあるかどうか(壊れたシンボリックリンクではないかどうか)をチェックし、ない場合は、で読み取り可能(必ずしも実行可能ではない)を検索the-scriptし$PATHます。
zshでshエミュレーションのように行うだろうbash場合ことを除いてthe-script、現在のディレクトリに壊れたシンボリックリンクで、それがために検索しないだろうthe-scriptに$PATH、代わりにエラーを報告します。
他のすべてのBourneのようなシェルはで検索the-scriptされません$PATH。
とにかく、これらすべてのシェルについて、が$0含まれておらず、/読み取りもできない場合は、おそらくで検索されてい$PATHます。次に、中のファイルは$PATH実行可能である可能性が高いcommand -v -- "$0"ので、そのパスを見つけるために使用するのはおそらく安全な概算です(ただし$0、ほとんどのシェルで組み込みのシェルまたはキーワードの名前である場合は機能しません)。
したがって、そのケースを本当にカバーしたい場合は、次のように書くことができます。
progname=$0
[ -r "$progname" ] || progname=$(
IFS=:; set -f
for i in ${PATH-$(getconf PATH)}""; do
case $i in
"") p=$progname;;
*/) p=$i$progname;;
*) p=$i/$progname
esac
[ -r "$p" ] && exec printf '%s\n' "$p"
done
exit 1
) && progname=$(readlink -e -- "$progname") ||
progname=unknown
(に""追加されているの$PATHは、セパレーターの代わりに区切り文字$IFSとして機能するシェルを持つ末尾の空の要素を保持することです)。
現在、スクリプトを呼び出すためのより難解な方法があります。次のことができます:
the-shell < the-script
または:
cat the-script | the-shell
その場合、$0はargv[0]、インタープリターが受け取った最初の引数()になります(上記のthe-shellですが、通常は、ベース名またはそのインタープリターへの1つのパスのいずれでもかまいません)。
の値に基づいてそのような状況にあることを検出することは$0信頼できません。ps -o args= -p "$$"手掛かりを得るためにの出力を見ることができます。パイプの場合、スクリプトへのパスに戻るための実際の方法はありません。
次のこともできます:
the-shell -c '. the-script' blah blih
次に、zsh(およびBourneシェルのいくつかの古い実装)を除いて、に$0なりますblah。繰り返しになりますが、これらのシェルでスクリプトのパスを取得するのは困難です。
または:
the-shell -c "$(cat the-script)" blah blih
等
適切$prognameであることを確認するには、次のようにして特定の文字列を検索します。
progname=$0
[ -r "$progname" ] || progname=$(
IFS=:; set -f
for i in ${PATH-$(getconf PATH)}:; do
case $i in
"") p=$progname;;
*/) p=$i$progname;;
*) p=$i/$progname
esac
[ -r "$p" ] && exec printf '%s\n' "$p"
done
exit 1
) && progname=$(readlink -e -- "$progname") ||
progname=unknown
[ -f "$progname" ] && grep -q 7YQLVVD3UIUDTA32LSE8U9UOHH < "$progname" ||
progname=unknown
しかし、繰り返しますが、努力する価値はないと思います。
$0、質問のタイトルに答える台本以外の何かがある状況について答えてきました。ただし、$0スクリプト自体は含まれているがディレクトリは含まれていない状況にも興味があります。特に、SOの回答に対するコメントを理解しようとしています。