Shell-Script

基於第二個文件中的模式匹配的第一個文件的映射欄位

  • November 26, 2020

我有兩個製表符分隔的文件,我需要將文件 1 第一列中的文本與文件 2 行中的任何位置進行匹配。匹配後,我想列印文件 1 匹配行的第二列中的內容到文件 2 中匹配行的末尾(範例如下)。

我知道這幾乎肯定可以用 awk 完成,但我不太擅長使用 awk 或 sed 並在這裡搜尋相關問題並嘗試調整他們的腳本並沒有為我解決。任何輸入將不勝感激。

文件 1

protein_1.p1     note "PJD5F7, match to databaseID=64575, (species X)";
protein_1.p2     note "PJD5F7, match to databaseID=64575, (species X)";
protein_3.p1     note "PA5F9H, match to databaseID=93689, (species W)";
protein_4.p1     note "Q7GT5J, match to databaseID=89045, (species Y)";
protein_4.p3     note "YE6G3L, match to databaseID=44968, (species Z)";

文件 2

chromosome_1    programID   transcript_id "protein_1.p1"; parent "protein_1";
chromosome_1    programID   transcript_id "protein_1.p2"; parent "protein_1";
chromosome_1    programID   transcript_id "protein_2.p1"; parent "protein_2";
chromosome_1    programID   transcript_id "protein_2.p2"; parent "protein_2";
chromosome_1    programID   transcript_id "protein_3.p1"; parent "protein_3";
chromosome_1    programID   transcript_id "protein_4.p1"; parent "protein_4";
chromosome_1    programID   transcript_id "protein_4.p2"; parent "protein_4";
chromosome_1    programID   transcript_id "protein_4.p3"; parent "protein_4";

期望的輸出

chromosome_1    programID   transcript_id "protein_1.p1"; parent "protein_1"; note "PJD5F7, match to databaseID=64575, (species X)";
chromosome_1    programID   transcript_id "protein_1.p2"; parent "protein_1"; note "PJD5F7, match to databaseID=64575, (species X)";
chromosome_1    programID   transcript_id "protein_2.p1"; parent "protein_2";
chromosome_1    programID   transcript_id "protein_2.p2"; parent "protein_2";
chromosome_1    programID   transcript_id "protein_3.p1"; parent "protein_3"; note "PA5F9H, match to databaseID=93689, (species W)";
chromosome_1    programID   transcript_id "protein_4.p1"; parent "protein_4"; note "Q7GT5J, match to databaseID=89045, (species Y)";
chromosome_1    programID   transcript_id "protein_4.p2"; parent "protein_4";
chromosome_1    programID   transcript_id "protein_4.p3"; parent "protein_4"; note "YE6G3L, match to databaseID=44968, (species Z)";

我們可以解析file1,將值 ( $2) 映射到鍵 ( ),然後當行 ( ) 的一部分與任何鍵匹配時$1,解析file2並將值附加到行。$3

BEGIN {OFS = FS = "\t"}
FNR == NR {arr[$1] = $2; next}
{for (x in arr) if ($3 ~ x) {$0 = $0 " " arr[x]; break}}
{print}

這將為您的範例列印正確的結果,但由於多種原因,這不是您想要的。第一個是它可能會在各種情況下失敗,比如protein_1.p1protein_1.p11。第二個原因是性能,file2 每一行的時間不是恆定的,而是file1.


所以我們要修改上面的腳本。您可能想為要匹配的蛋白質字元串定義一個正則表達式。這樣,匹配變得足夠嚴格,並且在第二次解析時,時間取決於匹配欄位上的正則表達式,而不是數組大小。

BEGIN {OFS = FS = "\t"; re = "\\<protein_[[:digit:]]+.p[[:digit:]]+\\>"}
FNR == NR {if ($1 ~ re) arr[$1] = $2; next}
match($3, re) {$0 = $0 " " arr[substr($3,RSTART,RLENGTH)]}
{print}

筆記:

  • re: “protein_” 後跟一個或多個數字,".p" 和一個或多個數字 所有這些都在 word 邊界內。點是字面意思。單詞字元是[:alnum:]_所以其餘的都是邊界。
  • 還有一個健全性檢查的第一個欄位file1
  • 如果match()找到 a ,則內置變數RSTARTRLENGTH保存匹配字元串的索引和長度,這個子字元串就是我們在雜湊中使用的。

用法:

> awk -f tst.awk file1 file2
chromosome_1    programID   transcript_id "protein_1.p1"; parent "protein_1"; note "PJD5F7, match to databaseID=64575, (species X)";
chromosome_1    programID   transcript_id "protein_1.p2"; parent "protein_1"; note "PJD5F7, match to databaseID=64575, (species X)";
chromosome_1    programID   transcript_id "protein_2.p1"; parent "protein_2"; 
chromosome_1    programID   transcript_id "protein_2.p2"; parent "protein_2"; 
chromosome_1    programID   transcript_id "protein_3.p1"; parent "protein_3"; note "PA5F9H, match to databaseID=93689, (species W)";
chromosome_1    programID   transcript_id "protein_4.p1"; parent "protein_4"; note "Q7GT5J, match to databaseID=89045, (species Y)";
chromosome_1    programID   transcript_id "protein_4.p2"; parent "protein_4"; 
chromosome_1    programID   transcript_id "protein_4.p3"; parent "protein_4"; note "YE6G3L, match to databaseID=44968, (species Z)";

引用自:https://unix.stackexchange.com/questions/621367