如何在同一个shell脚本中将一个进程的PID传递给另一个进程?

如何在同一个shell脚本中将一个进程的PID传递给另一个进程?

好吧,这可能是一个非常愚蠢的问题,而且我不经常编写 shell 脚本。我试图在后台启动 3 个进程,在 shell 脚本中一个接一个地启动,例如:

#!/bin/sh
PROCESS1 &
PROCESS2 &
PROCESS3 &

问题就在这里。我需要按照所示的相同顺序启动这些进程。此外,PROCESS2 的 PID 需要作为命令行参数传递给 PROCESS3。所有这些进程都在无限循环中运行,并且在 3 个独立的终端中运行时,它们确实可以顺利运行。

我试过:

#!/bin/sh
PROCESS1 &
PROCESS2 &
PID_PROCESS2=$!
PROCESS3 ${PID_PROCESS2} &

这将启动 PROCESS1 和 PROCESS3,但 PROCESS2 立即退出,不会打印任何错误。它就这样消失了。 ps 命令没有显示 PROCESS2 的痕迹。打印 PID_PROCESS2 返回某个值“p”,并且 PROCESS3 使用值“p”作为其参数运行得很好。我有什么问题和不足吗?

可能重要的细节

  1. 在上面的示例中,我使用限定路径来调用相应的进程,它们都是本机二进制文件并且位于同一目录中。例如,

     #!/bin/sh
     /usr/bin/PROCESS1 &
    

    ps 的输出如上所述,

     $ps | grep "/path/to/PROCESS"
     10064 root 16536 S /path/to/PROCESS1
     10066 root 11084 S /path/to/PROCESS3 10065
    

    它清楚地告诉 PROCESS2 已启动但由于某种未知原因退出。

  2. PROCESS2 通过 FIFO(命名管道)与 PROCESS1 进行通信,这是一种单向通信。

解决方法

#/bin/sh
/path/to/PROCESS1 &
/path/to/PROCESS2 & PROCESS2_PID=$!
export P2PID=${PROCESS2_PID}
sh -c "/path/to/PROCESS3 ${P2PID}"

这似乎为 sh 增加了一个额外的进程来完成这项工作。

$ps | grep "/path/to/PROCESS"
10174 root 16536 R /path/to/PROCESS1
10175 root 71720 S /path/to/PROCESS2
10177 root 27772 S sh -c /path/to/PROCESS3 10175
10076 root 11084 S /path/to/PROCESS3 100175

但我仍然不知道为什么会这样。有人可以建议在这种情况下发生了什么样的“魔法”吗?

答案1

根据您的描述,听起来 PROCESS2 存在根本性错误,导致其退出。如果我用 3 个进程对您所描述的内容进行建模,那么当您在后台运行 3 个进程,然后捕获第 2 个进程的 PID 并将其传递给进程 3 时,它基本上会按照预期工作。

例子

示例脚本
$ cat runny.bash
#!/bin/bash

proc3func() {
  echo $1
  sleep 7 &
}

sleep 9 &
sleep 8 &
PID2=$!
proc3func ${PID2} &
示例运行
$ ./runny.bash ; sleep 2; ps -eaf
4279
UID        PID  PPID  C STIME TTY          TIME CMD
...
vagrant   4278     1  0 20:21 pts/1    00:00:00 sleep 9
vagrant   4279     1  0 20:21 pts/1    00:00:00 sleep 8
vagrant   4282     1  0 20:21 pts/1    00:00:00 sleep 7

在上面的输出中,我们可以看到 PID 4279 被回显到屏幕上,后面的输出ps -eaf显示了我们的 3 个进程。

调试

我建议启用set -x,以便您可以在运行脚本时遵循正在执行的命令或像这样运行它:

$ bash -x ./runny.bash
+ PID2=4612
+ sleep 9
+ sleep 8
+ proc3func 4612
+ echo 4612
4612
+ sleep 7

相关内容