web-dev-qa-db-ja.com

シェルスクリプトがどのプログラムがそれを実行したかを知る方法はありますか?

* nixの世界で、シェルスクリプトがどのプログラムがそれを実行したかについての情報を持つ方法はありますか?


例:

/path/to/script1 /path/to/script_xyz

この架空のシナリオでは、script_xyzにはパス情報(/path/to/script1

または

プロセスPID

それを実行したエンティティの。

注:さまざまなソリューションやアプローチに興味がありますが、これが実際に可能であるとは思いません

13

プロセスの分岐と実行の間にはしばしば混乱があります。

bashシェルのプロンプトで行う場合。

$ sh -c 'exec env ps'

プロセスP1$プロンプトを発行すると、現在bashコードが実行されます。そのbashコードは新しいプロセスをフォークしますP2これは/bin/shを実行し、次に/usr/bin/envを実行し、次に/bin/psを実行します。

つまり、P2bashshenvおよび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の起動時に現在の作業ディレクトリからの相対パスになります。したがって、script1script2を呼び出す前に現在の作業ディレクトリを変更すると、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を取得できます。

23

はい、プログラムはその親が誰であるかを知ることができます。

説明のために、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 を参照してください。

8
John1024