在脚本中使用 pgrep 进行进程计数
using pgrep for process counting in a script
在我的 Raspbian 中,我使用了命令:
pgrep -c ^
我认为这个命令应该对所有进程进行计数,而不是使用更习惯的方法
ps -A --no-headers | wc -l
然而,当 运行 pgrep -c ^ 在脚本上时,(比如登录时),我想将 运行ning 进程的计数减去 1,以便调用 shell(例如 "sh")运行 脚本(或脚本本身)不算作一个过程...我不知道您是否在关注我。然后我开始用 pgrep 命令做一些实验
这是我的脚本示例:
#!/bin/sh
ps1=$(pgrep -c ^)
ps2=$(expr $(pgrep -c ^) - 1) # minus 1
ps3=$(expr $(pgrep -c ^) - 2) # minus 2
echo ${ps1}
echo ${ps2} # ps1 == ps2
echo ${ps3}
我得到的结果(在我的例子中):
112
112
111
a) 在脚本中,更改 ps1 和 ps2 的计算顺序没有任何区别。关键是 ps1 和 ps2 总是相等的(不知道为什么)。
b) 直接在提示符上输入相同的命令,如下所示:
$> pgrep -c ^; expr $(pgrep -c ^) - 1
显示(如预期):
111
110
c) 但是如果我修改命令以使用 echo:
$> echo "$(pgrep -c ^) : $(expr $(pgrep -c ^) - 1)"
甚至更改评估顺序:
"$> echo "$(expr $(pgrep -c ^) - 1) : $(pgrep -c ^)"
在这两种情况下,就像在脚本中一样,我得到:
112 : 112
问题:
1) 为什么在 script/echo 外部它按预期工作,但在脚本内部或内部和 echo/printf 值相同?
2) 命令 pgrep -c ^ 是计算 运行ning 进程的正确命令吗?
谢谢
这里的问题是您忽略了一个事实,即 shells 通过分叉自己来执行每个命令替换来创建一个单独的进程。
我承认 shell 的行为方式令人困惑。比如,举个例子:
$ pstree $$
sh───pstree
$ echo $(pstree $$)
sh───pstree
虽然我在上面另有说明,但似乎 sh
没有创建额外的进程来执行命令替换。但是,这是一种误解;它实际上确实进行了分叉,但是由于 $()
中只有一个命令,因此分叉的进程保持活动状态毫无意义;所以它只是通过调用 exec* 系列中的函数将自己替换为 pstree
;即它变成了 pstree
.
如果在 pstree
终止后还有另一个命令要执行,则分叉进程有必要保持活动状态。参见:
$ echo $(pstree $$; :)
sh───sh───pstree
嵌套命令替换的扩展也可能令人困惑,所以我们也澄清一下。
$ echo $(echo $(pstree $$))
sh───sh───pstree
对于上面的示例,由于每个命令替换只包含一个命令,因此人们可能希望在进程树中只看到一个 sh
;但事实并非如此。 $()
中包含的命令在为执行命令替换而创建的子 shell 中处理,而不是在父 shell 中处理。对于这种情况,这意味着;分叉进程制作了自己的另一个副本,以便能够执行 pstree
并收集其输出,然后执行 echo
;也就是说,当 pstree
是 运行 时,分叉进程还活着,因此树中有额外的 sh
。
因此,不要处理这些异常(以及我不知道或不记得的可能的其他异常),而是依赖 shell 的进程分组机制。喜欢:
pgrep -c ^
pgrep -cvg $$
echo $(pgrep -cvg $$)
echo $(echo $(pgrep -cvg $$))
echo $(echo $(echo $(pgrep -cvg $$)))
对我来说,它输出:
264
263
263
263
263
在我的 Raspbian 中,我使用了命令:
pgrep -c ^
我认为这个命令应该对所有进程进行计数,而不是使用更习惯的方法
ps -A --no-headers | wc -l
然而,当 运行 pgrep -c ^ 在脚本上时,(比如登录时),我想将 运行ning 进程的计数减去 1,以便调用 shell(例如 "sh")运行 脚本(或脚本本身)不算作一个过程...我不知道您是否在关注我。然后我开始用 pgrep 命令做一些实验
这是我的脚本示例:
#!/bin/sh
ps1=$(pgrep -c ^)
ps2=$(expr $(pgrep -c ^) - 1) # minus 1
ps3=$(expr $(pgrep -c ^) - 2) # minus 2
echo ${ps1}
echo ${ps2} # ps1 == ps2
echo ${ps3}
我得到的结果(在我的例子中):
112
112
111
a) 在脚本中,更改 ps1 和 ps2 的计算顺序没有任何区别。关键是 ps1 和 ps2 总是相等的(不知道为什么)。
b) 直接在提示符上输入相同的命令,如下所示:
$> pgrep -c ^; expr $(pgrep -c ^) - 1
显示(如预期):
111
110
c) 但是如果我修改命令以使用 echo:
$> echo "$(pgrep -c ^) : $(expr $(pgrep -c ^) - 1)"
甚至更改评估顺序:
"$> echo "$(expr $(pgrep -c ^) - 1) : $(pgrep -c ^)"
在这两种情况下,就像在脚本中一样,我得到:
112 : 112
问题:
1) 为什么在 script/echo 外部它按预期工作,但在脚本内部或内部和 echo/printf 值相同?
2) 命令 pgrep -c ^ 是计算 运行ning 进程的正确命令吗?
谢谢
这里的问题是您忽略了一个事实,即 shells 通过分叉自己来执行每个命令替换来创建一个单独的进程。
我承认 shell 的行为方式令人困惑。比如,举个例子:
$ pstree $$
sh───pstree
$ echo $(pstree $$)
sh───pstree
虽然我在上面另有说明,但似乎 sh
没有创建额外的进程来执行命令替换。但是,这是一种误解;它实际上确实进行了分叉,但是由于 $()
中只有一个命令,因此分叉的进程保持活动状态毫无意义;所以它只是通过调用 exec* 系列中的函数将自己替换为 pstree
;即它变成了 pstree
.
如果在 pstree
终止后还有另一个命令要执行,则分叉进程有必要保持活动状态。参见:
$ echo $(pstree $$; :)
sh───sh───pstree
嵌套命令替换的扩展也可能令人困惑,所以我们也澄清一下。
$ echo $(echo $(pstree $$))
sh───sh───pstree
对于上面的示例,由于每个命令替换只包含一个命令,因此人们可能希望在进程树中只看到一个 sh
;但事实并非如此。 $()
中包含的命令在为执行命令替换而创建的子 shell 中处理,而不是在父 shell 中处理。对于这种情况,这意味着;分叉进程制作了自己的另一个副本,以便能够执行 pstree
并收集其输出,然后执行 echo
;也就是说,当 pstree
是 运行 时,分叉进程还活着,因此树中有额外的 sh
。
因此,不要处理这些异常(以及我不知道或不记得的可能的其他异常),而是依赖 shell 的进程分组机制。喜欢:
pgrep -c ^
pgrep -cvg $$
echo $(pgrep -cvg $$)
echo $(echo $(pgrep -cvg $$))
echo $(echo $(echo $(pgrep -cvg $$)))
对我来说,它输出:
264
263
263
263
263