当通过其他命令管道传输时,pgrep 将返回额外的进程

当通过其他命令管道传输时,pgrep 将返回额外的进程

这是一个非常奇怪的问题,关于使用 pgrep 搜索哪些 shell 进程正在运行与当前脚本相同的脚本。

以下是测试脚本测试文件

#!/bin/bash

full_res=`pgrep -a -l -f 'test\.sh'`

res=$(pgrep -a -l -f 'test\.sh' | cat)

echo "short result is $full_res"

echo "weird result is $res"

输出为

sh test.sh &
[1] 19992
➜  logs short result is 19992 sh test.sh
weird result is 19992 sh test.sh
19996 sh test.sh

[1]  + 19992 done       sh test.sh

我不知道这个错误是从哪里来19996 sh test.sh的,尤其是在使用管道进行 cat 时。我相信这可能是 pgrep 实现的一个错误。

期待一些合理的解释

谢谢,

巴林

答案1

当您使用反引号创建管道或$(...)创建子 shell 时,它是您调用的原始 bash shell 的精确副本。

在执行 pgrep 时,您实际得到的是:

bash test.sh
  └─bash test.sh
      └─ pgrep -f test.sh
      └─ cat

所以这pgrep就是按照你要求的方式去做。

您可以像这样模拟这种行为。

#!/bin/bash
echo mypid $$
$(sleep 60 | sleep 60 | sleep 60)

在后台运行该进程,使用它吐出的 pid,用 进行检查pstree

$ ./test.bash 
mypid 335153
^Z
[1]+  Stopped                 ./test.bash
$ bg
[1]+ ./test.bash &
$ pstree -p 335153
test.bash(335153)───test.bash(335154)─┬─sleep(335155)
                                      ├─sleep(335156)
                                      └─sleep(335157)

答案2

管道在 bash 手册中:

在多命令管道中,创建管道的每个命令都在其自己的子 shell 中执行,这是一个单独的进程

顺便说一下,这就是为什么它不起作用的原因:

date | read theDate
echo "$theDate"

因为read命令在子 shell 中运行,所以theDate变量是在子 shell 中填充的,而不是在当前 shell 中。

相关内容