Shell脚本是否有办法知道哪个程序执行了它?


13

在* nix世界中,shell脚本是否可以获取有关哪个程序已执行该程序的信息?


例:

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

在这种假想的情况下,script_xyz将具有路径信息(/path/to/script1

要么

过程PID

执行它的实体。

注意:我对不同的解决方案和方法感到好奇,我不希望这真的可行


3
您的主题询问哪个程序执行了脚本。但是您的实际问题似乎是在要求脚本的解释器。您的问题到底是哪两个?
kasperd '16

@kasperd你是对的。问题是关于程序的,但实际上是解释程序。这就是为什么我觉得这不可能的原因。
米洛什Đakonović

Answers:


23

流程派生与执行之间经常会混淆。

当您在bashshell 提示下执行操作时。

$ 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上,另一个进程被指定为子收割者而不是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在调用之前更改了当前工作目录script2script2则会获得有关调用它的错误信息。因此,最$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死亡,则父进程可能会更改。

zshzsh/system模块中,可以使用来查询当前(子)shell 的当前父pid $sysparams[ppid]。在POSIX Shell中,您可以使用来获取执行解释器的进程的当前 ppid(假设它仍在运行)ps -o ppid= -p "$$"。使用bash,您可以使用来获取当前(子)shell的ppid ps -o ppid= -p "$BASHPID"


8

是的,程序可以知道其父级是谁。

为了说明,我们创建两个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的答案


谢谢。运行您的示例脚本我得到的s1s2PPID值,但随后,在经过多行ERROR: Unsupported SysV option.和几行额外解释和-空值Parent command
米洛什Đakonović

John正在使用您的平台上不可用(或以其他方式提供)的某些ps功能,请查看ps(1)手册页。
杰森

@Miloshio我使用版本3.3.12 psprocps-ng软件包对上述内容进行了测试。正如Jasen所建议的,您可能使用了不同的版本,这可能需要不同的语法来打印父级的命令行。尝试ps -f | grep $PPID
John1024 '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.