对 grep 忽略的行进行计数

Counting lines ignored by grep

提问人:coconut 提问时间:12/1/2011 最后编辑:Eric Wilsoncoconut 更新时间:12/6/2011 访问量:525

问:

让我试着尽可能清楚地解释这一点......

我有一个脚本,在某些时候可以这样做:

grep -vf ignore.txt input.txt

这个 ignore.txt 有一堆行,其中包含我希望我的 grep 忽略的内容,因此是 -v(这意味着我不想在 grep 的输出中看到它们)。

现在,我想做的是,我希望能够知道每行 ignore.txt 忽略了多少行输入 .txt。

例如,如果 ignore.txt 有以下行:

line1
line2
line3

我想知道通过忽略行 1 忽略了多少行输入 .txt,通过忽略行 2 忽略了多少行,依此类推。

关于我该怎么做的任何想法?

我希望这是有道理的......谢谢!

Perl sed awk grep

评论

0赞 Eric Wilson 12/1/2011
使用 grep 重要吗?或者您会考虑使用 或 ?sedawk
0赞 coconut 12/1/2011
sed 或 awk 也可以。这都是 perl 脚本的一部分,所以这也行得通。
0赞 coconut 12/2/2011
对不起,我的意思是与 ignore.txt 中的一行中的模式匹配的行数。

答:

0赞 Bubu 12/1/2011 #1

根据 unix.stackexchange

grep -o pattern file | wc -l

计算文件中给定模式的总数。鉴于此和您已经使用脚本的信息,一个解决方案是使用多个 grep 实例来过滤和计算您想要忽略的模式。

但是,我会尝试构建一个更舒适的解决方案,涉及脚本语言,例如 python。

评论

0赞 flesk 12/1/2011
这也是我的第一直觉,但这并不能解决他的问题,因为他不是要总数,而是要模式文件中每行的数。
0赞 Bubu 12/1/2011
@flesk好吧,如果我错了,请纠正我,但是如果他使用多个 grep 实例 - 阅读:每个模式一个实例 - 他会得到每个模式被忽略的行数,不是吗?至少在所描述的问题中是这样 - 给定每个模式都是要忽略的整行(上面给出的 忽略 .txt 示例)。
0赞 flesk 12/1/2011
他只使用了一个 grep 实例。该开关会从文件中生成 grep 读取模式,然后将其与 进行匹配。当你把它传递给你时,你只会得到总数。-finput.txtwc -l
0赞 musiKk 12/1/2011
最好使用而不是 .grep -cgrep ... | wc -l
0赞 sorpigal 12/2/2011
grep -o -f ignore.txt input.txt | sort | uniq -c会起作用,但这会为每个模式提供匹配,而不是非匹配。
1赞 tadmc 12/1/2011 #2

请注意,被忽略的行加上显示的行的总和可能不等于行总数...“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/;
}

评论

1赞 Dennis Williamson 12/4/2011
您在循环中重复(可能多次)调用外部实用程序,这不仅会多次生成实用程序,而且每次都会读取整个输入文件!Perl 可以在没有所有这些的情况下完成这项工作。grep
0赞 potong 12/1/2011 #3

这可能对你有用:

# 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

这显示了matchesignore.txt

 sed 's,.*,sed "/&/d;s/.*/non-matched &/" input.txt | uniq -c,' ignore.txt | sh

这显示了non-matchesignore.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

但是不,在大文件上,这实际上更慢。

0赞 TLP 12/2/2011 #4

此脚本将通过哈希查找来计算匹配的行,并保存要打印的行,您可以在其中随意处理它们。要模拟 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
        };
0赞 David W. 12/2/2011 #5

两者都有排序吗?ignore.txtinput.txt

如果是这样,您可以使用 comm 命令!

$ comm -12 ignore.txt input.txt

忽略了多少行?

$ comm -12 ignore.txt input.txt | wc -l

或者,如果要进行更多处理,请结合 .:commawk

$ 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 中 * 如果有两个选项卡,则该行位于两个文件中。commignore.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}'

评论

0赞 Dennis Williamson 12/4/2011
var++作品,是一个错别字,放在开头激怒了我(对不起),你可以省略外面的卷大括号和语句以及:和工作$oENDif()$0!/^\t/ {uniqtotal++}/^\t[^\t]/ {commtotal++}
0赞 David W. 12/6/2011
@DennisWilliamson - 感谢您发现错别字。我从我的测试中剪切并粘贴了这个。有时,在浏览帖子时,我会在发布之前解决问题。我有时会不小心删除某些内容并重新输入。也许这就是它的由来。你的大多数评论都是对的。我正在做一个快速测试,只是做了一些我知道有效的东西,即使打字要多一点。至于外侧大括号,我需要它们与我的 awk 版本一起使用。$o
0赞 Dennis Williamson 12/6/2011
awk 是什么版本?如果您使用 ,您需要外大括号,但如果您使用 ,则不需要它们(没有 ,正如我在之前的评论中描述的那样)。if/.../ {...}if
0赞 David W. 12/6/2011
@DennisWilliamson - 好的。我明白了,你仍然有大括号围绕着增量。将您建议的格式添加到我的答案中。
0赞 jmcnamara 12/2/2011 #6

这将打印被忽略的匹配项数以及匹配模式:

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 

更新:修改了上面的示例以使用字符串,以便输出更清晰一些。

评论

0赞 sorpigal 12/2/2011
这将计算模式的匹配项,而不是非匹配项。您需要从文件的总行数中减去每个模式的结果计数,以获得被忽略的行数。
0赞 jmcnamara 12/2/2011
@Sorpigal。差一点。它确实计算了匹配项的数量,但这些匹配项在 下运行时会被忽略。例如,针对上面创建的 25 行运行 OP 会给出 21 行数,即 4 行已被忽略。我上面的一行给出了这 4 条被忽略的行的细分。-v-vffile.txt
0赞 sorpigal 12/2/2011 #7
while IFS= read -r pattern ; do
        printf '%s:' "$pattern"
        grep -c -v "$pattern" input.txt
done < ignore.txt

grep对匹配的行进行计数,但对不匹配的行进行计数。因此,只需循环遍历模式并为每个模式计数一次。-c-v

评论

0赞 jmcnamara 12/2/2011
我们中的一个人有这个倒退。OP 要求“通过忽略 line1 来了解有多少行输入 .txt 被忽略”。您的代码似乎会计算模式未忽略的输入行数.txt这些行数。
0赞 sorpigal 12/2/2011
@jmcnamara:是的,我们中的一个人把它倒过来了。OP 通过从称为“忽略 .txt”的模式列表中请求“忽略的行”来混淆问题 - 忽略的行是否与忽略模式匹配?对我来说,措辞听起来像是不匹配的忽略是他想要的计数;我发布了一个澄清问题。
0赞 Dennis Williamson 12/4/2011
请参阅我对 tadmc 答案的评论。您可能要调用多次并且每次都读取整个文件。grep
0赞 sorpigal 12/5/2011
@DennisWilliamson:我知道。这不是一个非常有效的解决方案。如果效率如此重要,那么就需要一个更复杂的解决方案,无论是在perl还是在shell中。