Text-Processing

根據特定列將一行解構為兩行

  • May 7, 2017

我有一個包含1,965,056 行 14 列.tsv的文件 ( batch_1.catalog.tags.tsv) 。我想把其中的一些分成兩行

第一行:以大於號 (>) 開頭,後跟 14 列中的 8 列

第二行:僅第 10 列

例如。

>column3(a number) column4(numbers and letters) column5(a number) column6(- or +) column11(0 or 1) column12(0 or 1) column13(0 or 1) column14(0 or 1)       
column10(string with As,Ts,Gs,Cs, and sometimes Ns)    

這是.tsv文件第六行的範例,由第三列指定:

0   1   6   gi|586799556|ref|NW_006530744.1|    141 +   consensus   0   1_33,14_43  CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC    0   0   0   0    

這就是我想要的:

>6 gi|586799556|ref|NW_006530744.1| 141 +  0 0 0 0        
CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC    

但是,我只想對 tsv 文件 (batch_1.catalog.tags.tsv) 中具有與不同文本文件 (whitelist.txt) 中的數字匹配的第三列數字的行執行此操作。

在上面的範例中,whitelist.txt文件將包含數字 6,儘管還有 8000 多行具有不同的第三列數字(即 ID)。包括whitelist.txt最多 6 位數字。

我一直在嘗試另一種方法。我得到了下面的程式碼,用於使用白名單從.tsv文件中提取第 10 列。但是,grep 持續了 10 個小時,沒有做任何事情(空cat.fa文件)。

cat whitelist.txt | while read line; do zgrep "^0    1       $line   " batch_1.catalog.tags.tsv.gz; done | cut -f 3,10 | sed -E -e's/^([0-9]+)       ([ACGTN]+)$/>\1Z\2/' | tr "Z" "\n" > cat.fa    

下面使用 awk 或 perl 的兩種解決方案都可以完美執行。ID 也按順序列印出來,儘管它們在白名單中沒有按順序列印。perl 解決方案列印以製表符分隔的行,而 awk 列印以空格分隔的行。

awk解決方案:

假設來自batch_1.catalog.tags.tsv文件的測試片段:

0   1   6   gi|586799556|ref|NW_006530744.1|    141 +   consensus   0   1_33,14_43  CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC    0   0   0   0
1   2   7   hi|686711556|ref|NW_006530744.2|    141 +   consensus   0   1_33,14_43  CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC    1   1   0   1
2   2   8   hi|686711556|ref|NW_006530744.2|    141 +   consensus   0   1_33,14_43  CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC    1   1   1   1
3   3   9   th|776711556|ref|NW_006530744.2|    141 +   consensus   1   1_33,14_43  CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC    1   0   1   1

whitelight.txt以及來自文件的測試片段:

6
7
9

命令:

awk 'NR==FNR{ a[$0]++; next }{ if ($3 in a) { 
    $0=">"$3 FS $4 FS $5 FS $6 FS $11 FS $12 FS $13 FS $14 RS $10; print}}' whitelist.txt batch_1.catalog.tags.tsv > cat.fa

最終cat.fa內容:

>6 gi|586799556|ref|NW_006530744.1| 141 + 0 0 0 0
CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC
>7 hi|686711556|ref|NW_006530744.2| 141 + 1 1 0 1
CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC
>9 th|776711556|ref|NW_006530744.2| 141 + 1 0 1 1
CGGGCGGTGGTGGCGCACGCCTTTAATCCCAGCACTTGGGAGGCAGAGGCAGGTGGATCTTTGTGAGTTCGAGGCCAGCCTGGGCTACCAAGTGAGCTCC

詳情

NR==FNR- 對第一個文件執行操作,即whitelight.txt

a[$0]++;- 從whitelight.txt文件中累積數字

if ($3 in a)- 如果第二個文件中的第三列值與任何累積數字匹配,則允許採取行動

RS- awk 的記錄分隔符,預設為換行符

perl -F'\t+' -lane '
  @ARGV and $h{$F[0]}++,next;
  print ">", join("\t", @F[2..5,-4..-1]), $\, $F[9] if exists $h{$F[2]};
' whitelist.txt batch_1.catalog.tags.tsv

假設您的文件是 TAB 分隔的。

請注意,如果您的文件可能有 windows 或 mac 行尾,那麼謹慎的做法是首先通過實用程序 dos2unix 等將它們轉換為 unix 行尾(“\n”)。因為很多時候看到提供的程式碼沒有由於這些原因,在 OP 的最後工作。

工作

  • 注意何時Perl處理第一個參數(在這種情況下, @ whitelight.txtARGV 保存batch_1.catalog.tsv文件,即@ARGV = 1 => @ARGV 在布爾上下文中被評估為 TRUE。
  • @ARGV and $h{$F[0]}++,next應該解釋為:當我們在處理whitelight文件時,然後,將該文件的第一個欄位($F[0])添加到雜湊中,%h然後立即進入下一行。
  • 這些下面的任何行都將處理 TSV 文件,因為當時 @ARGV 沒有任何內容,因此計數為零。
  • 只有那些 TSV 文件記錄才能轉到標準輸出,其第三個欄位$F[2]恰好是%h散列中的鍵。
  • 一旦決定列印 TSV 記錄,則其列印格式為:(注意:OFS列印的預設值為NULL
  • ">",$F[2]表示第三個欄位前面有一個>
  • 欄位 4,5,6 =>@F[3..5]將被 TAB 分隔和連接。
  • 最後 4 個欄位 =>@F[-4..-1]將被 TAB 分隔並加入。
  • 第 10 個欄位$F[9]前面將有一個換行符,該換行符由$\= ORS=\n由於Perl選項而提供-l

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