Text-Processing
將新行轉換為製表符格式的文件
我有多個文件
SRR3384742.Gene.out.tab
SRR3384743.Gene.out.tab
SRR3384744.Gene.out.tab
,按這個順序還有更多。我正在從這些文件中提取第一列和第四列並將其儲存在輸出文件中。我試圖確保當我的腳本讀取一個新文件時,它應該以製表符分隔的方式提取數據,而不是在每個文件的末尾附加數據。輸入文件:
SRR3384742.Gene.out.tab
N_unmapped 313860 313860 313860 N_multimapping 5786679 5786679 5786679 N_noFeature 286816 31696770 438410 N_ambiguous 1283487 32117 65902 AT1G01010 301 0 301 AT1G01020 623 1 622 AT1G03987 5 5 0 AT1G01030 151 2 149
SRR3384743.Gene.out.tab
N_unmapped 780346 780346 780346 N_multimapping 4621162 4621162 4621162 N_noFeature 182428 28470016 362650 N_ambiguous 1451612 43059 117293 AT1G01010 154 3 151 AT1G01020 685 2 683 AT1G03987 0 0 0 AT1G01030 63 0 63
我得到的輸出:
SRR3384742.Gene.out.tab AT1G01010 301 AT1G01020 622 AT1G03987 0 AT1G01030 149 SRR3384743.Gene.out.tab AT1G01010 151 AT1G01020 683 AT1G03987 0 AT1G01030 63
所需的輸出:
SRR3384742.Gene.out.tab SRR3384743.Gene.out.tab AT1G01010 301 151 AT1G01020 622 683 AT1G03987 0 0 AT1G01030 149 63
我嘗試了以下腳本:
for sample in *Gene.out.tab; do echo -en $sample "\n"; awk 'NR>4 {print $1 "\t" $4}' $sample; awk '{print $0, $sample}' OFS='\t' $sample; done > output
這應該使用 GNU 為您提供註釋中描述的輸出
awk
:gawk 'FNR==1{names[c++]=FILENAME} FNR>4{ lines[$1] = "x"lines[$1] ? lines[$1]"\t"$4 : $4; } END{ for(i=0;i<=c;i++){ printf "\t%s",names[i] } printf "\n"; for(i in lines){ print i,lines[i] } }' *Gene.out.tab SRR3384742.Gene.out.tab SRR3384743.Gene.out.tab AT1G01010 301 151 AT1G01020 622 683 AT1G01030 149 63 AT1G03987 0 0
而且,為了讓它們在視覺上也很好地對齊,請通過
column
:$ gawk 'FNR==1{names[c++]=FILENAME}FNR>4{ lines[$1] = "x"lines[$1] ? lines[$1]"\t"$4 : $4; } END{ for(i=0;i<=c;i++){printf "\t%s",names[i];} printf "\n"; for(i in lines){ print i,lines[i]}}' *Gene.out.tab | column -s$'\t' -t SRR3384742.Gene.out.tab SRR3384743.Gene.out.tab AT1G01010 301 151 AT1G01020 622 683 AT1G01030 149 63 AT1G03987 0 0
FNR
是一個特殊的 awk 變數,它始終保存正在處理的目前文件的行號。FILENAME
是一個 GNUawk
特殊變數,它保存目前正在處理的文件的名稱。
FNR==1{names[c++]=FILENAME}
: 如果這是其中一個輸入文件的第一行,則使用該變數c
作為names
其值為文件名的數組的索引,並將其值遞增 yb 1 (c++
)。處理完所有文件後,files[0]
將是第一個文件名,files[1]
將是第二個,依此類推。FNR>4{ lines[$1] = "x"lines[$1] ? lines[$1]"\t"$4 : $4; }
:這相當於:if(FNR>4){ if("x"lines[$1]){ lines[$1]"\t"$4 else{ lines[$1] = $4 } }
如果目前輸入文件的行號為 5 或更多,請檢查第一個欄位是否在數組中具有關聯值
lines
。我們檢查使用"x"lines[$i]
,因為如果lines[$1]
是0
,那麼測試將是假的,但x0
它是真的,所以x
可以防止這種情況。因此,如果我們確實有一個值,我們將一個製表符和目前行的第二個欄位附加到它,如果我們沒有一個值,我們將它設置為目前行的第四個欄位。
END{ ... }
:在處理完所有輸入後執行此操作。for(i=0;i<=c;i++){printf "\t%s",names[i]}; printf "\n";
:列印數組中的每個文件名names
,前面有一個製表符。我們希望前導選項卡確保我們在標題行和內容中具有相同數量的欄位。列印文件名後,列印一個換行符。for(i in lines){print i,lines[i]}
:對於lines
數組的每個索引,列印索引(ID),然後列印在第一步中儲存的相關值。限制:這需要將所有輸出數據儲存在記憶體中。這在現代機器上真的不應該是一個問題,因為我們只儲存 ID 並且每個文件每個 ID 只儲存一個值,因此它應該能夠在相當不錯的機器上阻塞之前處理大量輸入,但它可能會成為一個大量數據的問題。