使用 grep 计算出现的总次数

313 grep

grep -c对于查找字符串在文件中出现的次数很有用,但它每行只计算每次出现一次。如何计算每行出现的多次?

我正在寻找比以下更优雅的东西:

perl -e '$_ = <>; print scalar ( () = m/needle/g ), "\n"'
Run Code Online (Sandbox Code Playgroud)

wag*_*wag 456

grep-o只会输出匹配项,忽略行;wc可以计算它们:

grep -o 'needle' file | wc -l
Run Code Online (Sandbox Code Playgroud)

这也将匹配“针”或“多针”。

要仅匹配单个单词,请使用以下命令之一:

grep -ow 'needle' file | wc -l
grep -o '\bneedle\b' file | wc -l
grep -o '\<needle\>' file | wc -l
Run Code Online (Sandbox Code Playgroud)

  • @Geek \b 匹配词边界,\B 不匹配词边界。如果在两端都使用 \b ,上面的答案会更正确。 (8认同)
  • 请注意,这需要 GNU grep(Linux、Cygwin、FreeBSD、OSX)。 (7认同)
  • @JivanPal这是在“uniq -c”的上下文中,“sort”无法做到这一点。当然,如果您知道相同的行总是相邻的,则根本不需要“排序”,如果您的模式只是一个静态字符串,则它们将是这样,但在一般情况下则不需要。 (2认同)

Gil*_*il' 20

如果您有 GNU grep(总是在 Linux 和 Cygwin 上,偶尔在其他地方),您可以计算来自grep -o:的输出行数grep -o needle | wc -l

使用 Perl,这里有一些我觉得比你的更优雅的方法(即使在它被修复之后)。

perl -lne 'END {print $c} map ++$c, /needle/g'
perl -lne 'END {print $c} $c += s/needle//g'
perl -lne 'END {print $c} ++$c while /needle/g'
Run Code Online (Sandbox Code Playgroud)

仅使用 POSIX 工具,如果可能,一种方法是将输入拆分为具有单个匹配项的行,然后再将其传递给 grep。例如,如果您要查找整个单词,则首先将每个非单词字符转换为换行符。

# equivalent to grep -ow 'needle' | wc -l
tr -c '[:alnum:]' '[\n*]' | grep -c '^needle$'
Run Code Online (Sandbox Code Playgroud)

否则,没有标准命令来进行这种特定的文本处理,因此您需要求助于 sed(如果您是受虐狂)或 awk。

awk '{while (match($0, /set/)) {++c; $0=substr($0, RSTART+RLENGTH)}}
     END {print c}'
sed -n -e 's/set/\n&\n/g' -e 's/^/\n/' -e 's/$/\n/' \
       -e 's/\n[^\n]*\n/\n/g' -e 's/^\n//' -e 's/\n$//' \
       -e '/./p' | wc -l
Run Code Online (Sandbox Code Playgroud)

这是一个使用sedand的更简单的解决方案grep,它适用于字符串甚至是书本的正则表达式,但在一些带有锚定模式的极端情况下失败(例如,它找到了^needle\bneedlein 的两次出现needleneedle)。

sed 's/needle/\n&\n/g' | grep -cx 'needle'
Run Code Online (Sandbox Code Playgroud)

请注意,在上面的 sed 替换中,我过去\n指的是换行符。这是模式部分的标准,但在替换文本中,为了可移植性,将反斜杠换行替换为\n.


OJF*_*ord 7

如果像我一样,你真的想要“两个;每个都恰好一次”,(这实际上是“一个;两次”),那么这很简单:

grep -E "thing1|thing2" -c
Run Code Online (Sandbox Code Playgroud)

并检查输出2

这种方法的好处(如果恰好一次你想要的)是,它很容易扩展。

  • @rugk你完全错过了OP帖子中的第一句话,它明确解释了“-c”仅计算每行**一次**出现的次数。如果一个字符串在同一行出现 1000 次,`grep -c` 仍然只会将其计为 1。这个答案对于这个问题来说根本没有任何意义。 (6认同)