在* nix世界中,shell脚本是否可以获取有关哪个程序已执行该程序的信息?
例:
/path/to/script1 /path/to/script_xyz
在这种假想的情况下,script_xyz
将具有路径信息(/path/to/script1
)
要么
过程PID
执行它的实体。
注意:我对不同的解决方案和方法感到好奇,我不希望这真的可行
在* nix世界中,shell脚本是否可以获取有关哪个程序已执行该程序的信息?
例:
/path/to/script1 /path/to/script_xyz
在这种假想的情况下,script_xyz
将具有路径信息(/path/to/script1
)
要么
过程PID
执行它的实体。
注意:我对不同的解决方案和方法感到好奇,我不希望这真的可行
Answers:
流程派生与执行之间经常会混淆。
当您在bash
shell 提示下执行操作时。
$ 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
。
然后,它可以向系统查询该进程当前正在运行的命令(例如readlink /proc/<pid>/exe
在Linux上),或者将传递给它所执行的最后一个命令的参数(例如与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 shell中,$PPID
将包含在该shell初始化时执行该shell的进程的父进程的pid。之后,如上所示,如果id进程$PPID
死亡,则父进程可能会更改。
zsh
在zsh/system
模块中,可以使用来查询当前(子)shell 的当前父pid $sysparams[ppid]
。在POSIX Shell中,您可以使用来获取执行解释器的进程的当前 ppid(假设它仍在运行)ps -o ppid= -p "$$"
。使用bash
,您可以使用来获取当前(子)shell的ppid ps -o ppid= -p "$BASHPID"
。
是的,程序可以知道其父级是谁。
为了说明,我们创建两个bash脚本。第一个报告其PID,并启动第二个脚本:
$ cat s1.sh
#!/bin/bash
echo s1=$$
bash s2.sh
第二个脚本报告其进程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
如您所见,实际上第二个脚本确实知道其父级的PID。使用ps
,该PID会显示用于调用父级的命令行。
有关PPID的更深入讨论,请参阅StéphaneChazelas的答案。
s1
,s2
和PPID
值,但随后,在经过多行ERROR: Unsupported SysV option.
和几行额外解释和-空值Parent command
ps
的procps-ng
软件包对上述内容进行了测试。正如Jasen所建议的,您可能使用了不同的版本,这可能需要不同的语法来打印父级的命令行。尝试ps -f | grep $PPID
。