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)
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.
如果像我一样,你真的想要“两个;每个都恰好一次”,(这实际上是“一个;两次”),那么这很简单:
grep -E "thing1|thing2" -c
Run Code Online (Sandbox Code Playgroud)
并检查输出2。
这种方法的好处(如果恰好一次是你想要的)是,它很容易扩展。