首页 > 解决方案 > pgrep {进程名称} | wc -l 返回错误结果

问题描述

我有这个脚本(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给出正确的结果。有什么帮助吗?

提前致谢!

标签: linuxshellwc

解决方案


所以首先我们./test.sh从终端做。所以我们有一个带有进程名称的进程test.sh

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

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

例如,这可以通过以下方式进行检查:

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是子shell的495463pid,是父shell进程的pid。

当你这样做时:

pids=`pgrep 'test.sh'`;

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

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

额外:更多子壳!以下

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

推荐阅读