假设我想看看已经运行了多少个程序副本。我可以这样做:
ps ax | grep -c "$0"
该命令本身产生预期结果。但是如果我尝试将输出分配给变量,它会增加1!无论我如何尝试:
var=$(ps ax | grep "$0" | sed -n '$=')
var=`ps ax | grep -c "$0"`
有人可以告诉我正确的方法来捕获正确的输出吗?
了解为什么会发生这种情况也很棒。
UPDATE 在@fedorqui的第一个回复后,我意识到我不够清楚。让我详细说明:
我在同一个bash脚本中运行上面的所有三个命令。当我运行第一个时,它打印出数字2:程序本身和以该程序作为参数的grep进程。当我在变量赋值中运行相同的命令时,会存储数字3。
请注意我使用两种不同的计数线,grep和sed的方法。在这两种情况下,他们都返回3而不是正确答案,2。
这是一个在test.sh文件中尝试的合并示例:
echo -n "without assignment: "
ps ax | grep -c "$0"
var=$(ps ax | grep "$0" | sed -n '$=')
echo "using sed method: $var"
var=`ps ax | grep -c "$0"`
echo "using grep method: $var"
我的debian框上的结果:
without assignment: 2
using sed method: 3
using grep method: 3
问题:为什么会发生这种情况,以及如何预防或解决这些问题?
答案 0 :(得分:3)
引用Siegex:
由于
grep
正在返回ps
进程本身。
您可以选择其中之一:
"特技"
grep
围绕其中一个搜索不匹配 字符类[ ]
中的字符,它们不会更改 功能性:
或者,在这种情况下,
管道到grep -v grep
,以便流程不匹配:
var=$(ps ax | grep -v grep | grep "$0")
查看示例。我们在这里有一个流程sleep
:
$ sleep 20 &
[1] 5602
如果我们在ps
的输出中检查它,它会出现两次!
$ ps -ef| grep sleep
me 5602 5433 0 09:49 pts/2 00:00:00 sleep 20
me 5607 5433 0 09:49 pts/2 00:00:00 grep --colour=auto sleep
所以我们可以使用一个字符类:
$ ps -ef| grep [s]leep
me 5602 5433 0 09:49 pts/2 00:00:00 sleep 20
或者grep grep过程:
$ ps -ef| grep sleep | grep -v grep
me 5602 5433 0 09:49 pts/2 00:00:00 sleep 20
答案 1 :(得分:1)
命令替换本身在子shell中运行,因此只有一个bash
进程
您搜索bash
($0
),即grep -c bash
也会在当时的流程表中结束,以便包含字符串的另一个进程(grep
) bash
。请注意,这可能不会在运行时显示在流程表中,具体取决于系统的繁忙程度。
你有两个(或其他)实际的bash
进程(会话)可能正在运行
您可以使用正则表达式技巧来消除假阳性,即grep
来自计数:
ps ax | grep -c "[b]ash"
在执行命令替换时,它仍将计算子shell:
var=$(ps ax | grep -c "[b]ash")
因此您需要手动从此计数中删除一个。
示例:强>
$ var=$(ps ax | grep -c "bash")
$ echo $var
4
$ var=$(ps ax | grep -c "[b]ash")
$ echo $var
3
答案 2 :(得分:0)
您的命令也会计算grep命令行。
ps ax | grep -v grep | grep -c "$0"
应该省略计数中的grep