bash:将结果赋给变量时的换行计数不同

时间:2016-05-10 07:37:56

标签: bash shell scripting

假设我想看看已经运行了多少个程序副本。我可以这样做:

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

问题:为什么会发生这种情况,以及如何预防或解决这些问题?

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也会在当时的流程表中结束,以便包含字符串的另一个进程(grepbash。请注意,这可能不会在运行时显示在流程表中,具体取决于系统的繁忙程度。

  • 你有两个(或其他)实际的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