grep 如何返回不同数量的匹配项?

gab*_*abt 2 grep pattern-matching

我需要将一个文件(24 行)grep 成两个文件(有点大)。

原始文件包含与此字符串类似的 24 行:

AATGGACGCTTAAC[A|C|T][A|C|G]CGGC[A|T]TCGGAT
Run Code Online (Sandbox Code Playgroud)

我执行以下操作:

grep -f aList hugeFile_N*.csv | wc -l
4396868
Run Code Online (Sandbox Code Playgroud)

然后,为了仔细检查一切是否正常,我将文件分成两个文件,并通过另一个 grep 使用它们:

cat aList | head -n 12 > firstHalf
cat aList | tail -n +13 > secondHalf
grep -f firstHalf hugeFile_N*.csv | wc -l
2169008
grep -f secondHalf hugeFile_N*.csv | wc -l
2228046
Run Code Online (Sandbox Code Playgroud)

现在,我期望来自两个单独 grepped 文件的匹配总数等于我为原始文件找到的匹配数。但是,正如你所看到的:

2169008 + 2228046 = 4397054
4397054 != 4396868
Run Code Online (Sandbox Code Playgroud)

不是这种情况。我们有 186 场比赛缺失。这里发生了什么?

我还对(实际上非​​常简单的)文件进行了一些调查。在这里,我从两个独立的部分 grep 结果:

grep -f <(cat firstHalf secondHalf) hugeFile_N*.csv > together
Run Code Online (Sandbox Code Playgroud)

然后我分别 grep 两半:

grep -f firstHalf hugeFile_N*.csv > separately
grep -f secondHalf hugeFile_N*.csv >> separately
Run Code Online (Sandbox Code Playgroud)

而且,正如已经显示的,匹配的数量是不同的:

wc -l together
4396868 together
wc -l separately
4397054 separately
Run Code Online (Sandbox Code Playgroud)

但是,唯一匹配的数量是相同的:

sort -u together | wc -l
3735836
sort -u separately | wc -l
3735836
Run Code Online (Sandbox Code Playgroud)

有趣的是,如果我 grep 原始文件中的两半,我根本没有匹配项。我想知道为什么会这样:

grep -f ../code/firstHalf ../code/aList | wc -l
0
grep -f ../code/secondHalf ../code/aList | wc -l
0
Run Code Online (Sandbox Code Playgroud)

我 100% 确定这两部分都存在,aList因为我可以用我的编辑器看到它(它们各有 12 行,所以用肉眼看也不难)。

我觉得我做错了grep什么,但是……什么?

中的所有行aList都是唯一的。

ilk*_*chu 12

grep只查找至少匹配给定模式之一的行。有 24 个模式aList,上半场的一个和下半场的一个匹配是可能的。这将意味着你会得到两个同一直线上比赛grep -f firstHalfgrep -f secondHalf。分别运行模式列表的两半会重复计算这些行。

例如

$ cat test.txt 
abc 
foo
bar
foobar
$ cat patterns 
foo
bar
$ grep -c -f patterns  test.txt 
3
Run Code Online (Sandbox Code Playgroud)

但当然还有:

$ grep -c -e foo test.txt
2
$ grep -c -e bar test.txt
2
Run Code Online (Sandbox Code Playgroud)

并且 2+2 > 3。

如果所有行都是不同的,那么计算唯一匹配的行当然是消除这种影响的一种方法。您可以使用grep -n向输出添加行号,使每个输出行唯一。当然请记住,默认情况下会grep查找行中任何位置的匹配项,如果这不是您想要的,则需要使用grep -x.

另请注意,这[A|C|T]意味着匹配任何字符A, C,T|。如果您不想或不需要匹配管道字符,请仅使用[ACT]. 或者,如果您需要交替,则必须使用扩展正则表达式 ( grep -E),然后(this|that)(带括号,而不是方括号)。但是,只要所有替代项都是单个字符,就没有必要。

  • @gabt,嗯,在某种程度上,是的。`-f` 给出的文件中的行是 _patterns_,而不是固定字符串。模式可以匹配多行,多个模式可以匹配同一行。所以没有1:1的关系。至于拆分列表,就像问一群学生有多少人选了 A 课,有多少人选了 B 课。这些数字的总和可能与选了 A 或 B 的学生数量不同(即已经采取了A和B中的至少一个)。事实上,总数可能高于学生总数。 (3认同)