shell脚本有办法知道哪个程序执行了它吗?

shell脚本有办法知道哪个程序执行了它吗?

在*nix世界中,shell脚本有没有办法获得有关哪个程序执行了它的信息?


例子:

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

在这个假想的场景中,script_xyz将有路径信息 ( /path/to/script1)

或者

过程PID

执行它的实体。

注意:我对不同的解决方案和方法感到好奇,我并不认为这实际上是可能的

答案1

进程分叉和执行之间经常会出现混淆。

当您在 shell 的提示下执行此操作时bash

$ sh -c 'exec env ps'

过程P1发出该$提示当前正在运行bash代码。该bash代码派生了一个新进程P2执行/bin/sh然后执行/usr/bin/env,然后执行/bin/ps

所以P2依次执行了bashshenv和的代码ps

ps(或任何其他命令,例如我们在此处使用的脚本)无法知道该env命令是否已执行它。

它所能做的就是找出它的父进程 ID 是什么,在本例中可以是P1或者1如果P1在此间隔内死亡,或者在 Linux 上另一个被指定为副收割者代替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在调用之前更改当前工作目录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"

答案2

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

为了说明这一点,我们创建两个 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éphane Chazelas 的回答

相关内容