* nixの世界で、シェルスクリプトがどのプログラムがそれを実行したかについての情報を持つ方法はありますか?
例:
/path/to/script1 /path/to/script_xyz
この架空のシナリオでは、script_xyz
にはパス情報(/path/to/script1
)
または
プロセスPID
それを実行したエンティティの。
注:さまざまなソリューションやアプローチに興味がありますが、これが実際に可能であるとは思いません
プロセスの分岐と実行の間にはしばしば混乱があります。
bash
シェルのプロンプトで行う場合。
$ sh -c 'exec env ps'
プロセスP1$
プロンプトを発行すると、現在bash
コードが実行されます。そのbash
コードは新しいプロセスをフォークしますP2これは/bin/sh
を実行し、次に/usr/bin/env
を実行し、次に/bin/ps
を実行します。
つまり、P2はbash
、sh
、env
およびps
のコードを実行しました。
ps
(または、ここで代わりに使用するスクリプトのような他のコマンド)は、env
コマンドによって実行されたことを知る方法がありません。
それができることは、その親プロセスIDが何であるかを見つけることです。この場合、P1または1
のいずれかになりますP1がインターバルで終了した場合、またはLinuxの別のプロセスの場合1
ではなく subreaper として指定されています。
次に、そのプロセスが実行しているコマンドをシステムに照会できます現在実行中(Linuxのreadlink /proc/<pid>/exe
など)または実行した最後のコマンドに渡される引数(ps -o args= -p <pid>
など)。
スクリプトにそれを呼び出したものを認識させたい場合、信頼できる方法は、呼び出し側にそれを通知させることです。これは、たとえば環境変数を介して行うことができます。たとえば、script1
は次のように書くことができます。
#! /bin/sh -
INVOKER=$0 script2 &
そしてscript2
:
#! /bin/sh -
printf '%s\n' "I was invoked by $INVOKER"
# and in this case, we'll probably find the parent process is 1
# (if not now, at least one second later) as script1 exited just after
# invoking script2:
ps -fp "$$"
sleep 1
ps -fp "$$"
exit
$INVOKER
には( 一般に )にscript1
へのパスが含まれます。ただし、相対パスの場合もあります。このパスは、script1
の起動時に現在の作業ディレクトリからの相対パスになります。したがって、script1
がscript2
を呼び出す前に現在の作業ディレクトリを変更すると、script2
は、それが何と呼ばれたかについて誤った情報を取得します。したがって、$INVOKER
を次のように記述することにより、script1
に絶対パスが含まれていることを確認することをお勧めします(ベース名を維持することが望ましい)。
#! /bin/sh -
mypath=$(
mydir=$(dirname -- "$0") &&
cd -P -- "$mydir" &&
pwd -P) && mypath=$mypath/$(basename -- "$0") || mypath=$0
... some code possibly changing the current working directory
INVOKER=$mypath script2
POSIXシェルでは、$PPID
には、そのシェルの初期化時にシェルを実行したプロセスの親のpidが含まれます。その後、上記のように、id $PPID
のプロセスが停止すると、親プロセスが変更される可能性があります。
zsh/system
モジュールのzsh
は、$sysparams[ppid]
を使用して、現在の(サブ)シェルのcurrent親pidを照会できます。 POSIXシェルでは、ps -o ppid= -p "$$"
を使用して、インタプリタを実行しているプロセスのcurrent ppid(まだ実行中であると想定)を取得できます。 bash
を使用すると、ps -o ppid= -p "$BASHPID"
で現在の(サブ)シェルのppidを取得できます。
はい、プログラムはその親が誰であるかを知ることができます。
説明のために、2つのbashスクリプトを作成してみましょう。最初のスクリプトはPIDを報告し、2番目のスクリプトを開始します。
$ cat s1.sh
#!/bin/bash
echo s1=$$
bash s2.sh
2番目のスクリプトは、プロセスID、その親のPID、および親の実行に使用されるコマンドラインを報告します。
$ cat s2.sh
#!/bin/bash
echo s2=$$ PPID=$PPID
echo "Parent command: $(ps -o cmd= -q $PPID)"
それでは、実行してみましょう。
$ bash s1.sh
s1=17955
s2=17956 PPID=17955
Parent command: bash s1.sh
ご覧のとおり、2番目のスクリプトは実際にその親のPIDを知っています。 ps
を使用すると、そのPIDは親を呼び出すために使用されるコマンドラインを明らかにします。
PPIDの詳細については、StéphaneChazelasの answer を参照してください。