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


13

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


例:

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

この想像上のシナリオでscript_xyzは、パス情報(/path/to/script1

または

プロセスPID

実行したエンティティの

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


3
あなたの主題は、どのプログラムがスクリプトを実行したかを尋ねます。しかし、実際の質問は、スクリプトのインタープリターを求めているようです。あなたの質問はどちらですか?
カスペルド

@kasperdあなたは正しい。質問はプログラムについてでしたが、それは実際には通訳です。だから、そもそもこれは不可能だと思っていました。
ミロシュ・チャコノヴィッチ

回答:


23

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

bashシェルのプロンプトで行うとき。

$ sh -c 'exec env ps'

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

だからP2順番にのコードを実行したbashshenvps

ps(またはここで代わりに使用するスクリプトのような他のコマンド)は、envコマンドによって実行されたことを知る方法がありません。

それは行うことができますすべては、このケースではどちらかと思われる、その親プロセスIDが何であるかを見つけることですP1または1場合P1として指定されている別のプロセス間隔でまたはLinux上で死亡したsubreaperの代わりに1

次に、そのプロセスがどのコマンドであるかをシステムに照会できます 現在実行(readlink /proc/<pid>/exeLinuxの場合など)または実行した最後のコマンドに渡された引数(など)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すると、親プロセスが変更される場合があります。

zshzsh/system、モジュール、照会することができ、現在と現在の(サブ)シェルの親のpidを$sysparams[ppid]。POSIXシェルでは、でインタープリターを実行しているプロセスの現在の ppidを取得できます(まだ実行されていると仮定)ps -o ppid= -p "$$"。ではbash、あなたが現在(サブ)シェルのPPIDを取得することができますps -o ppid= -p "$BASHPID"


8

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

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


ありがとう。あなたの例の私が得るスクリプト実行s1s2およびPPID後に複数行で、その後、値をが、ERROR: Unsupported SysV option.空の値-追加説明として、いくつかのラインParent command
ミロシュĐakonović

Johnは、プラットフォームで利用できない(または別の方法で提供される)いくつかのps機能を使用しています。ps(1)のマニュアルページを確認してください。
-Jasen

@Miloshio パッケージ、バージョン3.3.12 を使用psして上記をテストしましたprocps-ng。Jasenが提案したように、親のコマンドラインを印刷するために異なる構文を必要とする可能性のある異なるバージョンを使用している可能性があります。試してくださいps -f | grep $PPID
John1024
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.