pgrep {process_name} | wc -l 返回错误结果

pgrep {process_name} | wc -l returning wrong results

我有这个脚本 (test.sh):

#!/bin/bash

echo "pgreg --- start"
pgrep 'test.sh'
echo "pgrep --- end"

process_count=`pgrep 'test.sh' | wc -l`
echo "process_count = $process_count"

pids=`pgrep 'test.sh'`;
fixed_count_process=`echo $pids | wc -w`
echo "pids = $pids";
echo "fixed_count_process = $fixed_count_process"

此脚本的输出总是:

pgreg --- start
56516
pgrep --- end
process_count = 2
pids = 56516
fixed_count_process = 1

我找不到任何合乎逻辑的解释,为什么在将 pgrep 的输出传递给 wc 之前将其存储在变量中会给出正确的结果。有帮助吗?

提前致谢!

因此,首先我们从终端执行 ./test.sh。所以我们有一个进程名称为 test.sh.

的进程
process_count=`pgrep 'test.sh' | wc -l`

反引号调用的命令替换运行是一个子shell。 subshell 是一个单独的进程并且具有相同的进程名称test.sh。所以现在有两个具有不同 pid 的进程,它们的进程名称为 test.sh。因此 pgrep returns 两行。

这可以通过以下方式检查:

process_count=$(
        ps -e -o pid,comm | grep 'test.sh' >&2
        echo BASHPID=$BASHPID $=$$ >&2
        pgrep 'test.sh' | wc -l
)

在 stderr 上输出:

 495463 test.sh
 495466 test.sh
BASHPID=495466 $=495463

495466 是子进程的 pidshell,495463 是父进程的 pid shell。

当你这样做时:

pids=`pgrep 'test.sh'`;

这会输出一个 pid。这是因为 bash 有一个优化,在特定情况下(例如没有 traps)当 shell 中只剩下一个进程执行时,它会优化并且不会调用fork()+exec() 相反,它只调用 exec,因为 运行 没有下一个进程,所以它可以直接退出。进程名称为 test.sh 的内部 subshell 仅存在很短的时间,subshell 检测到只有一个命令到 运行,因此它会跳过 fork(),就执行了exec("pgrep"),变成了进程名pgrep的进程。这就是为什么在这种情况下您看不到另一个 pid 的原因。

注意:请不要使用反引号`。请改用 $(...)

额外:更多子shell!以下

echo "$(echo "$(echo "$(pgrep 'test.sh' | wc -l)")")"
# would output 4