2016-11-22 82 views
2

我秀例如什麼,我需要做的:如何分割文件根據第一列awk的

輸入:

name value1 value2 value3 
john xxxxx yyyyy qqqqqq 
john xxxxx ddddd vvvvvv 
john mmmmm jjjjj llllll 
paul xxxxx yyyyy qqqqqq 
paul ccccc ccccc dddddd 

,我需要根據相同名稱,以保持頭和拆分後的文件在第一列。 我需要根據第一列來命名我的輸出文件。

輸出:

FILE1:john.tsv

name value1 value2 value3 
john xxxxx yyyyy qqqqqq 
john xxxxx ddddd vvvvvv 
john mmmmm jjjjj llllll 

FILE2:paul.tsv

name value1 value2 value3 
paul xxxxx yyyyy qqqqqq 
paul ccccc ccccc dddddd 

輸入和輸出文件是標籤分開。標題始終相同。

我的解決方案是非常複雜和緩慢:

head -1 INPUT > header 

awk 'NR>1{print $1}' | sort | uniq > names 

while read line 

do grep $line INPUT | cat header - > $line.tsv 

< names 

done 
+0

是他們排序?例如:所有'john'條目總是彼此相鄰? – Sundeep

+0

Yeas總是按名稱排序。 – Paul

+0

更好地編輯與排序要求的問題,也改變樣本輸入和預期的輸出,以反映排序 – Sundeep

回答

3

數據部分的排序的所有迄今公佈的答案有問題,這將使他們的脆弱和/或非便攜式的(例如使用getline而不檢查它的結果,輸出重定向的右側未使用,使用gawk特有的功能,以及在完成輸出文件時不關閉)和/或不必要的複雜。

由第一2列進行排序輸入文件,同時保留標題是:

$ awk -v OFS='\t' '{print (NR>1), $0}' file | sort | cut -f2- 
name value1 value2 value3 
john mmmmm jjjjj llllll 
john xxxxx ddddd vvvvvv 
john xxxxx yyyyy qqqqqq 
paul ccccc ccccc dddddd 
paul xxxxx yyyyy qqqqqq 

和強勁,便攜,高效打印您的輸入,包括標題行到單獨的文件命名基於第一列是:

$ cat tst.awk 
NR==1 { hdr=$0; next } 
$1 != prev { 
    close(out) 
    out = $1 ".tsv" 
    print hdr > out 
    prev = $1 
} 
{ print > out } 

所以把它放在一起會是:

awk -v OFS='\t' '{print (NR>1), $0}' file | sort | cut -f2- | awk -f tst.awk 
+0

埃德謝謝你的好解決方案。將有可能請使用您的awk代碼,如終端中的一個班輪?我嘗試使用:awk'NR == 1 {hdr = $ 0;下一步} $ 1!= prev {close(out)out = $ 1「.csv」print hdr> out prev = $ 1} {print> out}'infile。但它不起作用。 – Geroge

+1

當然,只需用';'替換每一個換行符,除了緊跟在'{'之後的那個換行符。 –

+1

偉大的是現在的作品。非常感謝! – Geroge

5

使用awk我們可以寫一些像

$ awk 'NR == 1{header = $0; next} 
    !($1 in filename){ print header > ($1".tsv") } 
    NR > 1 { print $0 > ($1".tsv"); filename[$1] }' file 

它能做什麼?

  • NR == 1{header = $0}如果記錄的讀取數量爲1,這是標題,將其保存在header供以後使用。

  • NR > 1 { print $0 > ($1".tsv"); filename[$1] }如果我們已經閱讀了多條記錄,請將該行的內容打印到文件名$1即第一列。

    • filename[$1]我們將文件名保存在由文件名索引的關聯數組中。該數組用於打印出標題。
  • ($1 in filename){ print header > ($1".tsv") }如果我們在filename數組中找不到當前文件名,那麼這是第一次出現。所以我們打印出文件頭。


編輯

如果你想在第二列中的文件進行排序,那麼我們可以先進行排序,然後將它們管awk一樣,

$ sort -n -k2 file | awk .... 
  • -n數字排序。
  • -k2按第二個鍵排序。

這個可能不起作用,如果頭也是數字。

+3

建議'awk'NR == 1 {header = $ 0;下一個}!($ 1的文件名){print header> $ 1「.tsv」} {print $ 0> $ 1「.tsv」;文件名[$ 1]}'',以避免爲頭文件創建以及匹配文件擴展名預計由OP – Sundeep

+0

@Sundeep oops,我錯過了。感謝您指出。 – nu11p01n73R

+0

您複製了我尚未發佈的答案! –

2

類似@ nu11p01n73R的回答,添加腳本

$ awk 'NR==1{h=$0; next} 
    !p[$1]++{print h > $1} 
      {print | "sort -k2 >> " $1}' file 

$ head paul john 

==> paul <== 
name value1 value2 value3 
paul ccccc ccccc dddddd 
paul xxxxx yyyyy qqqqqq 

==> john <== 
name value1 value2 value3 
john mmmmm jjjjj llllll 
john xxxxx ddddd vvvvvv 
john xxxxx yyyyy qqqqqq 
+0

謝謝你的幫助。我有這個錯誤信息:NR == 1 {h = $ 0;下一頁}!p [$ 1] ++ {print h> $ 1} {print | 「sort -k2 >>」>>> $ <<< 1} awk:源代碼行1的非法聲明 - 任何想法? – Paul

+1

是你的腳本,像我發佈的單引號? – karakfa

+0

未定義的輸出重定向是每個POSIX未定義的行爲,因此可能是導致OP語法錯誤的原因。 $ 1可能包含空格,因此您需要引用它。切換輸出文件時,可能需要關閉()管道。 –

相關問題