2015-06-24 106 views
3

我想知道是否有更有效的方法来使用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,那将非常感谢!

回答

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

+0

这也会匹配'chr0'。如果这不是有意的,我们可以重构一点。 – fedorqui

+0

@BlueMoon是真的!没有检查完整的解释,只是样本输入/期望输出。更新,谢谢。 – fedorqui

+0

非常酷!如果我理解代码$ 1-特定的第一列。 “〜”?? “〜”的功能是什么? 。我不知道什么是“1”?正在做..你介意详细介绍一下吗? :) – Learner

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
+0

非常感谢:)如此优雅! :)在冰中有没有一个地方指出我们只搜索第一列?你是一个真正的! :) – Learner

+0

@学习者在正则表达式中定位'^'意味着我们将始终从该行的*开头*开始匹配,但它并不真正意识到“列”。使用awk的'$ 1'的另一个答案将在第一个字段上进行操作,这是由默认 – arco444

+0

欢呼声分隔的空白字符,感谢解释@ arco444 – Learner

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 

正如你可以在上面看到,你甚至可以添加注释的模式列表,使用\|招(EN用\|来定义每个模式),所以你可以记住你昨天做了什么或者你在哪里找到正则表达式。您可以通过添加新行来添加新的固定字符串或模式。另外,如果你发现很难创建一个复杂的正则表达式,你可能只需创建一个特征码文件要匹配固定字符串:

^chrX 
^chrY 
... 

这种方法的另一个好处是,你可以保持几个病毒码文件,代表您可能需要每天运行的不同子查询。例如。

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

这种方法的唯一缺点是grep会变慢,如果你不是在每个文件十几模式添加更多。但是,只有当你的输入文件有成千上万行时,这将是一个问题。

0

鉴于您发布的例子,所有你需要得到你想要的输出或者是这些(或其他简单的RE):

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

,所以你可能没有列出具体的“模式”,具体视你的真实世界要求。

-1

下面会做这个工作。

grep -v -w 'random'