使用grep在许多文件中计算一个字符串的所有出现次数

334

我有一堆日志文件。我需要找出一个字符串在所有文件中出现的次数。

grep -c string *

返回

...
file1:1
file2:0
file3:0
...

使用管道,我可以获取只包含一个或多个出现的文件:

grep -c string * | grep -v :0

...
file4:5
file5:1
file6:2
...

我如何仅获取合并计数?(如果它返回file4:5、file5:1、file6:2,我想获取8。)


1
你能告诉我 grep -v :0 是什么意思吗?我知道它计算出现次数大于0的文件。-v选项和:0代表什么?请告诉我。 - Gautham Honnavara
2
@gauthamhonnavara grep :0 查找与字符串 :0 匹配的行。-v 是一个选项,用于反转搜索,因此使用 grep -v :0 表示查找不包含 :0 的所有行,因此具有文件4:5和文件27:193的行都将通过,因为它们不包含 :0。 - penguin359
您可以使用空格选择多个文件。grep file1 file2 --options - Dnyaneshwar Harer
16个回答

331

这适用于每行出现多次的情况:

grep -o string * | wc -l

2
这个也可以:grep -o string * --exclude-dir=some/dir/one/ --exclude-dir=some/dir/two | wc -l - a coder
3
我用grep -ioR string * | wc -l来进行大小写不敏感、递归、仅匹配搜索的操作。 - LeonardChallis
3
这个命令会显示相关的文件以及匹配的总数:grep -rc test . | awk -F: '$NF > 0 {x+=$NF; $NF=""; print} END{print "Total:",x}' - Yaron
请注意grep的限制:https://superuser.com/questions/1703029/is-there-a-limit-for-a-line-length-for-grep-command-to-process-correctly - duplex143

303
cat * | grep -c string

10
这有一个限制,即同一行中出现多次的只计算一次。不过我猜在这种情况下这种行为是可以接受的。 - Michael Haren
2
我宁愿做 grep -c string<*,所以只需要用小于号取代空格。 - JamesM-SiteGen
55
不涉及同一行中多个事件的情况。 - bluesman
2
如果你想要在子目录中搜索,这种方法就不起作用了,而grep -owc -l则可以。但是像原始问题那样,使用cat会更快。 - Leagsaidh Gordon
有点不相关,但这正是我来这里希望得到的并且可能会帮助其他人:这对于 git grep 不起作用,因为它没有 -o,但是 git grep <word> | grep -c <word> 可以。就像被接受的答案一样,在一行中有多个出现的情况下是不准确的。git grep <word> | grep -o <word> | wc -l 将涵盖该情况。 - eggsyntax
显示剩余2条评论

28
grep -oh string * | wc -w

将在一行中计算多个出现次数


30
把“...我的咖喱真辣”从所有文件中筛选出来,并将结果传给 wc 命令。 - icc97
@icc97 你是想将管道传输到 wc 还是 cwc(咒骂词计数)? - Matiaan

26

不要使用-c,只需将其管道传递给wc -l。

grep string * | wc -l

以下代码会将每个出现的字符串单独列为一行,并统计行数。

但是,如果一个字符串在同一行中出现了两次及以上,则不会被计算。


2
使用管道符号连接“wc -l”和“grep -r' test' .”非常方便,它可以递归扫描当前目录下所有子目录中的所有文件,查找字符串“test”。 - Stephan Kristyn

18
cat * | grep -c string

cat 的罕见有用应用之一。


13
如果您想要统计每个文件中特定字符串的出现次数(以“tcp”为例):
grep -RIci "tcp" . | awk -v FS=":" -v OFS="\t" '$2>0 { print $2, $1 }' | sort -hr

示例输出:

53  ./HTTPClient/src/HTTPClient.cpp
21  ./WiFi/src/WiFiSTA.cpp
19  ./WiFi/src/ETH.cpp
13  ./WiFi/src/WiFiAP.cpp
4   ./WiFi/src/WiFiClient.cpp
4   ./HTTPClient/src/HTTPClient.h
3   ./WiFi/src/WiFiGeneric.cpp
2   ./WiFi/examples/WiFiClientBasic/WiFiClientBasic.ino
2   ./WiFiClientSecure/src/ssl_client.cpp
1   ./WiFi/src/WiFiServer.cpp

解释:

  • grep -RIci NEEDLE . - 从当前目录(遵循符号链接)递归查找字符串NEEDLE,忽略二进制文件,计算出现次数,忽略大小写
  • awk ... - 此命令会忽略出现次数为零的文件并格式化行
  • sort -hr - 按第一列中的数字以相反顺序排序行

当然,它也适用于其他带有选项-c(计数)的grep命令。例如:

grep -c "tcp" *.txt | awk -v FS=":" -v OFS="\t" '$2>0 { print $2, $1 }' | sort -hr

太棒了!像魔法一样好用。省下了好几天时间。非常感谢你。 - sreejagaths

13

你可以添加-R进行递归搜索(避免使用cat),并添加-I以忽略二进制文件。

grep -RIc string .

12

必不可少的 AWK 解决方案:

grep -c string * | awk 'BEGIN{FS=":"}{x+=$2}END{print x}'

如果您的文件名包含 ":",请小心处理。


12

与之前所有答案不同的是:

perl -lne '$count++ for m/<pattern>/g;END{print $count}' *

很高兴看到有一种不使用grep的方法,尤其是我的Windows上的grep不支持-o选项。 - David Roussel

7

下面是一种处理包括冒号在内的文件名的 AWK 解决方案:

grep -c string * | sed -r 's/^.*://' | awk 'BEGIN{}{x+=$1}END{print x}'

请记住,这种方法仍然不能在同一行上找到多个string的出现。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接