提问人:coconut 提问时间:12/1/2011 最后编辑:Eric Wilsoncoconut 更新时间:12/6/2011 访问量:525
对 grep 忽略的行进行计数
Counting lines ignored by grep
问:
让我试着尽可能清楚地解释这一点......
我有一个脚本,在某些时候可以这样做:
grep -vf ignore.txt input.txt
这个 ignore.txt 有一堆行,其中包含我希望我的 grep 忽略的内容,因此是 -v(这意味着我不想在 grep 的输出中看到它们)。
现在,我想做的是,我希望能够知道每行 ignore.txt 忽略了多少行输入 .txt。
例如,如果 ignore.txt 有以下行:
line1
line2
line3
我想知道通过忽略行 1 忽略了多少行输入 .txt,通过忽略行 2 忽略了多少行,依此类推。
关于我该怎么做的任何想法?
我希望这是有道理的......谢谢!
答:
grep -o pattern file | wc -l
计算文件中给定模式的总数。鉴于此和您已经使用脚本的信息,一个解决方案是使用多个 grep 实例来过滤和计算您想要忽略的模式。
但是,我会尝试构建一个更舒适的解决方案,涉及脚本语言,例如 python。
评论
-f
input.txt
wc -l
grep -c
grep ... | wc -l
grep -o -f ignore.txt input.txt | sort | uniq -c
会起作用,但这会为每个模式提供匹配,而不是非匹配。
请注意,被忽略的行加上显示的行的总和可能不等于行总数...“Line1 和 Line2 are here”将被计算两次。
#!/usr/bin/perl
use warnings;
use strict;
local @ARGV = 'ignore.txt';
chomp(my @pats = <>);
foreach my $pat (@pats) {
print "$pat: ", qx/grep -c $pat input.txt/;
}
评论
grep
这可能对你有用:
# seq 1 15 | sed '/^1/!d' | sed -n '$='
7
解释:
删除除匹配行之外的所有行。通过管道将这些匹配(忽略)的行传递给另一个命令。删除所有这些行,但仅显示最后一行的行号。因此,在此示例 1 到 15 中,忽略第 1、10 到 15 行 - 总共 7 行。sed
编辑:
对不起,误读了这个问题(还是有点困惑!
sed 's,.*,sed "/&/!d;s/.*/matched &/" input.txt| uniq -c,' ignore.txt | sh
这显示了matches
ignore.txt
sed 's,.*,sed "/&/d;s/.*/non-matched &/" input.txt | uniq -c,' ignore.txt | sh
这显示了non-matches
ignore.txt
如果使用 ,这些也应该有效:GNU sed
sed 's,.*,sed "/&/!d;s/.*/matched &/" input.txt | uniq -c,;e' ignore.txt
或
sed 's,.*,sed "/&/d;s/.*/non-matched &/" input.txt | uniq -c,;e' ignore.txt
注意您在模式方面的成功可能会有所不同,即事先检查元字符。
经过反思,我认为这可以改进为:
sed 's,.*,/&/i\\matched &,;$a\\d' ignore.txt | sed -f - input.txt | sort -k2n | uniq -c
或
sed 's,.*,/&/!i\\non-matched &,;$a\\d' ignore.txt | sed -f - input.txt | sort -k2n | uniq -c
但是不,在大文件上,这实际上更慢。
此脚本将通过哈希查找来计算匹配的行,并保存要打印的行,您可以在其中随意处理它们。要模拟 grep,只需打印它们即可。@result
我制作了脚本,以便它可以打印出一个示例。要与文件一起使用,请取消注释脚本中的代码,并注释标记为 .# example line
法典:
use strict;
use warnings;
use v5.10;
use Data::Dumper; # example line
# Example data.
my @ignore = ('line1' .. 'line9'); # example line
my @input = ('line2' .. 'line9', 'fo' .. 'fx', 'line2', 'line3'); # example line
#my $ignore = shift; # first argument is ignore.txt
#open my $fh, '<', $ignore or die $!;
#chomp(my @ignore = <$fh>);
#close $fh;
my @result;
my %lookup = map { $_ => 0 } @ignore;
my $rx = join '|', map quotemeta, @ignore;
#while (<>) { # This processes the remaining arguments, input.txt etc
for (@input) { # example line
chomp; # Required to avoid bugs due to missing newline at eof
if (/($rx)/) {
$lookup{$1}++;
} else {
push @result, $_;
}
}
#say for @result; # This will emulate grep
print Dumper \%lookup; # example line
输出:
$VAR1 = {
'line6' => 1,
'line1' => 0,
'line5' => 1,
'line2' => 2,
'line9' => 1,
'line3' => 2,
'line8' => 1,
'line4' => 1,
'line7' => 1
};
两者都有排序吗?ignore.txt
input.txt
如果是这样,您可以使用 comm 命令!
$ comm -12 ignore.txt input.txt
忽略了多少行?
$ comm -12 ignore.txt input.txt | wc -l
或者,如果要进行更多处理,请结合 .:comm
awk
$ comm ignore.txt input.txt | awk '
END {print "Ignored lines = " igtotal " Lines not ignored = "commtotal " Lines unique to Ignore file = " uniqtotal}
{
if ($0 !~ /^\t/) {uniqtotal+=1}
if ($0 ~ /^\t[^\t]/) {commtotal+=1}
if ($0 ~ /^\t\t/) {igtotal+=1}
}'
在这里,我利用了命令放置在输出中的选项卡:
* 如果没有制表符,则该行仅在中。
* 如果有一个选项卡,则它仅在输入 .txt 中
* 如果有两个选项卡,则该行位于两个文件中。comm
ignore.txt
顺便说一句,并非所有行都被忽略。如果该行不在输入 .txt 中,则不能说该行被忽略。ignore.txt
丹尼斯·威廉姆森(Dennis Williamson)的建议
comm ignore.txt input.txt | awk '
!/^\t/ {uniqtotal++}
/^\t[^\t]/ {commtotal++}
/^\t\t/ {igtotal++}
END {print "Ignored lines = " igtotal " Lines not ignored = "commtotal " Lines unique to Ignore file = " uniqtotal}'
评论
var++
作品,是一个错别字,放在开头激怒了我(对不起),你可以省略外面的卷大括号和语句以及:和工作$o
END
if()
$0
!/^\t/ {uniqtotal++}
/^\t[^\t]/ {commtotal++}
$o
if
/.../ {...}
if
这将打印被忽略的匹配项数以及匹配模式:
grep -of ignore.txt input.txt | sort | uniq -c
例如:
$ perl -le 'print "Coroline" . ++$s for 1 .. 21' > input.txt
$ perl -le 'print "line2\nline14"' > ignore.txt
$ grep -of ignore.txt input.txt | sort | uniq -c
1 line14
3 line2
即,与“line14”匹配的行被忽略一次。与“line2”匹配的行被忽略 3 次。
如果您只想计算忽略的总行数,这将起作用:
grep -cof ignore.txt input.txt
更新:修改了上面的示例以使用字符串,以便输出更清晰一些。
评论
-v
-vf
file.txt
while IFS= read -r pattern ; do
printf '%s:' "$pattern"
grep -c -v "$pattern" input.txt
done < ignore.txt
grep
对匹配的行进行计数,但对不匹配的行进行计数。因此,只需循环遍历模式并为每个模式计数一次。-c
-v
评论
grep
上一个:查找具有相似和不同字段的记录
下一个:将方法应用于流
评论
sed
awk