如何匹配特定列中的多个模式?

时间:2015-06-24 11:07:45

标签: bash unix awk grep pattern-matching

我想知道是否有更有效的方法来使用awk / grep / sed来解决以下问题?

我想解析输入文件的某一列(在此示例中为第1列),并使用awk / grep /任何其他函数来子集并选择与我的查询匹配的模式。例如,给出以下文件;

chr1    3009844 3009908 DXX 42  -
chr2    3000386 3000450 DXX 15  -
chr3    3000386 3000450 DXX 15  -
chr4    3000386 3000450 DXX 15  -
chr5    3000386 3000450 DXX 15  -
chr6    3000386 3000450 DXX 15  -
chr7    3000386 3000450 DXX 15  -
chr8    3000386 3000450 DXX 15  -
chr9    3000386 3000450 DXX 15  -
chr10   3000386 3000450 DXX 15  -
chr11   3000386 3000450 DXX 15  -
chr12   3000386 3000450 DXX 15  -
chr13   3000386 3000450 DXX 15  -
chr14   3000386 3000450 DXX 15  -
chr15   3000386 3000450 DXX 15  -
chr16   3000386 3000450 DXX 15  -
chr17   3000386 3000450 DXX 15  -
chr18   3000386 3000450 DXX 15  -
chr19   3000386 3000450 DXX 15  -
chrX    3000386 3000450 DXX 15  -
chrY    3000386 3000450 DXX 15  -
chr1_GL456210_random    3000386 3000450 DXX 15  -
chr1_GL456211_random    3000386 3000450 DXX 15  -
chr1_GL456212_random    3000386 3000450 DXX 15  -
chr1_GL456221_random    3000386 3000450 DXX 15  -
chr4_GL456216_random    3000386 3000450 DXX 15  -
chr4_JH584292_random    3000386 3000450 DXX 15  -
chr4_JH584295_random    3000386 3000450 DXX 15  -
chr5_GL456354_random    3000386 3000450 DXX 15  -
chr5_JH584296_random    3000386 3000450 DXX 15  -
chr5_JH584297_random    3000386 3000450 DXX 15  -
chr5_JH584299_random    3000386 3000450 DXX 15  -
chrX_GL456233_random    3000386 3000450 DXX 15  -

我只想输出第一列中只有chr1-chr22,chrX和chrY的输出,例如;

chr1    3009844 3009908 DXX 42  -
chr2    3000386 3000450 DXX 15  -
chr3    3000386 3000450 DXX 15  -
chr4    3000386 3000450 DXX 15  -
chr5    3000386 3000450 DXX 15  -
chr6    3000386 3000450 DXX 15  -
chr7    3000386 3000450 DXX 15  -
chr8    3000386 3000450 DXX 15  -
chr9    3000386 3000450 DXX 15  -
chr10   3000386 3000450 DXX 15  -
chr11   3000386 3000450 DXX 15  -
chr12   3000386 3000450 DXX 15  -
chr13   3000386 3000450 DXX 15  -
chr14   3000386 3000450 DXX 15  -
chr15   3000386 3000450 DXX 15  -
chr16   3000386 3000450 DXX 15  -
chr17   3000386 3000450 DXX 15  -
chr18   3000386 3000450 DXX 15  -
chr19   3000386 3000450 DXX 15  -
chrX    3000386 3000450 DXX 15  -
chrY    3000386 3000450 DXX 15  -

我设法使用以下命令找到解决方案:

awk '$1 == "chr1" || $1 == "chr2" || $1 == "chr3" || $1 == "chr4" || $1 == "chr5" || $1 == "chr6" || $1 == "chr7" || $1 == "chr8" || $1 == "chr9" || $1 == "chr10" || $1 == "chr11" || $1 == "chr12" || $1 == "chr13" || $1 == "chr14" || $1 == "chr15" || $1 == "chr16" || $1 == "chr17" || $1 == "chr18" || $1 == "chr19" || $1 == "chr20" || $1 == "chrX" || $1 == "chrY"'  in_file > out_file

它运作正常,但是想知道亲爱的成员是否会有更优雅的方法来解决问题?或者,如果您可以指向资源来探索linux中的awk / grep,那将非常感激!

5 个答案:

答案 0 :(得分:3)

使用正则表达式:

awk '$1 ~ /^chr(1?[0-9]|2[0-2]|X|Y)$/' file

这使用$1 ~ /^pattern$/来选择完全由pattern组成的好行(注意^表示开头,$表示结尾。)

该模式位于chr(..|..|..)表单上,表示:匹配chr后跟|()分隔的条件之一。

这些条件可以是:

  • 一个数字(可能是1后跟一个数字)(1?[0-9]
  • 数字为2 + 0,1,2(2[0-2]
  • 中的任何一个
  • X
  • ý

演示自动解释:https://regex101.com/r/gH1kS4/2

答案 1 :(得分:2)

如果您想要更容易维护(例如编辑或添加新的行/模式以匹配)以及更容易理解的内容,特别是如果您刚刚开始使用正则表达式,请使用grep -f match.list input.txt格式:

创建一个包含您要匹配的模式的文件(match.list):

^chr[1-9][[:space:]]\|      # this matches chr1-chr9
^chr1[0-9][[:space:]]\|     # this matches chr10-chr19
^chr2[12][[:space:]]\|      # this matches chr21-22
^chr[XY][[:space:]]\|       # this matches chrX and chrY
new_string_or_pattern\|     # ... your new pattern ...

然后就这样打电话给grep

grep -f match.list input.txt

正如您在上面所看到的,您甚至可以使用\|技巧(使用\|结束每个模式)在模式列表中添加注释,这样您就可以记住您昨天所做的或者在哪里你找到了正则表达式吗?您可以通过添加新行来添加新的固定字符串或模式。此外,如果您发现很难创建复杂的正则表达式,您可能只需创建一个包含您想要匹配的固定字符串的模式文件:

^chrX
^chrY
...

此方法的另一个好处是您可以维护多个模式文件,表示您可能需要每天运行的不同子查询。 E.g。

grep -f chromosomes_n input.txt
grep -f chromosomes_xy input.txt
grep -f chromosomes_random input.txt

该方法的唯一缺点是,如果在每个文件中添加十几个模式,grep会变慢。但只有当您的输入文件包含数十万行时,这才会成为问题。

答案 2 :(得分:1)

您可以将这个简化的正则表达式与grep

一起使用
grep "^chr\(1\?[0-9]\|2[012]\|[XY]\)[[:space:]]" filename

逻辑包含在括号\(..\)

  • 1\?[0-9] - 匹配0-9,可选地以1
  • 开头
  • 2[012] - 匹配2,然后是0,1或2
  • [XY] - 匹配X或Y

答案 3 :(得分:0)

根据您发布的示例,您需要获得所需的输出(或其他简单的RE):

awk '$1 !~ /_/' file
awk '$1 ~ /^[[:alnum:]]+$/' file

因此您可能根本不需要列出具体的“模式”,具体取决于您的实际需求。

答案 4 :(得分:-1)

以下将完成工作。

grep -v -w 'random'