我有一个文件,需要计算文件中输入字符串的所有部分匹配项。
我将向您展示我需要的一个简单的示例:
在包含以下内容的文件中:
Good-Black-Cat
Bad-Red-Cat
Bad-Gray-Dog
Good-Golden-Dog
Bad-White-Dog
Good-Tabby-Cat
Bad-Siamese-Cat
我需要计算部分字符串“Good -*-Cat”(其中 * 可以是任何数字,无所谓)出现的次数。预期输出次数为 2。
任何帮助将不胜感激。
答案1
鉴于
$ cat file
Good-Black-Cat
Bad-Red-Cat
Bad-Gray-Dog
Good-Golden-Dog
Bad-White-Dog
Good-Tabby-Cat
Bad-Siamese-Cat
然后
$ grep -c 'Good-.*-Cat' file
2
请注意,这是一个匹配行数- 例如,它不适用于每行多次出现的情况,或者跨越多行出现的情况。
或者,使用awk
awk '/Good-.*-Cat/ {n++} END {print n}' file
如果您需要每行匹配多个可能的出现情况,那么我建议perl
:
perl -lne '$c += () = /Good-.*?-Cat/g }{ print $c' file
匹配/Good-.*?-Cat/g
多次(g
)和非贪婪*(.*?
)并且() =
赋值强制在标量上下文中评估匹配,以便我们可以将它们添加到计数中。
或者,您可以grep
在 perl 兼容正则表达式(PCRE)模式中使用(以启用非贪婪修饰符),-o
仅输出匹配的部分 - 然后计算以下部分wc
:
grep -Po 'Good-.*?-Cat' file | wc -l
perl
如果您还需要匹配可能跨越行边界的出现,那么您可以通过取消设置记录分隔符(注意:这意味着整个文件被吸入内存)并添加正则表达式修饰符来实现s
,例如
perl -0777 -nE '$c += () = /Good-.*?-Cat/gs }{ say $c' file
答案2
awk,多次出现,以空格分隔
$ awk '{for(i=1;i<=NF;i++ ) count+=match($i,/Good-.*-Cat/)};END{print count}' input.txt
4
$ cat input.txt
Good-Black-Cat
Bad-Red-Cat
Bad-Gray-Dog
Good-Golden-Dog Good-Whatever-Cat Good-Something-Cat
Bad-White-Dog
Good-Tabby-Cat
Bad-Siamese-Cat
sed + wc,非多次出现
这使用负模式匹配//!
来d
删除,只留下感兴趣的行。
$ sed '/Good-.*-Cat/!d' input.txt
Good-Black-Cat
Good-Golden-Dog Good-Whatever-Cat
Good-Tabby-Cat
$ sed '/Good-.*-Cat/!d' input.txt | wc -l
3
壳解决方案,非多次出现
case...esac
这里是结合文件读取循环的shell 方式:
$ n=0; while IFS= read -r line || [ -n "$line" ]; do case "$line" in "Good-"*"-Cat") n=$((n+1));; esac; done < input.txt; echo "$n"
2
或者使用指示
n=0
while IFS= read -r line || [ -n "$line" ]; do
case "$line" in
"Good-"*"-Cat") n=$((n+1));;
esac
done < input.txt
echo "$n"
解释:
n=0
初始化n
计数器变量while IFS= read -r line || [ -n "$line" ]; do...done < input.txt
是 shell 脚本中使用的标准文件读取循环,具有|| [ -n "$line" ]
保护功能,可以处理可能不以换行符结尾的文件case "$line" in "Good-"*"-Cat") n=$((n+1));; esac
对所需字符串进行模式匹配,并使用$((...))
算术扩展来增加计数器变量。
答案3
普通版 sed/grep
sed 's/\(Good-[^ ]*-Cat\)/XXXX\n/g' input.txt | grep -c XXXX
虽然XXXX
可以是文件中未出现的任何模式。此方法将所有匹配项替换为模式XXXX
和换行符,以便通过基本的 grep 表达式轻松计数。
顺便说一句,如果你从字面上理解“其中 * 可以是任何东西”,至少据我理解,任何此类程序的输出始终为 0 或 1,因此我假设它至少不应包含空格。