2015-06-24 105 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'