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 firstHalf
和grep -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)
(带括号,而不是方括号)。但是,只要所有替代项都是单个字符,就没有必要。