2011-10-18 52 views
1

我有一個文件中的多個「表」,如:聯盟「表」使用awk

col1, col2, col3, col4 
1, 2, 3, 4 
5, 6, 7, 8 

col2, col3, col5 
10, 11, 12 
13, 14, 15 

,我想這兩個表崩:

col1, col2, col3, col4, col5 
1 , 2 , 3 , 4 , 
5 , 6 , 7 , 8 , 
    , 10 , 11 ,  , 12 
    , 13 , 14 ,  , 15 

(注:只是爲了使事情更容易理解,額外的空格)

這似乎需要至少2遍,一個收集列的完整列表,另一個創建輸出表。用awk可以做到這一點嗎?如果不是,你會推薦什麼其他工具?

+0

一個解決方法是創建file2,其中已經有空列那麼問題就簡單多了,否則你希望這是動態的,並且具有讀取頭文件'col1,ol2 ...'的共同點的邏輯?祝你好運 – shellter

+1

join(1)命令幾乎可以滿足你的需求。您可以嘗試編寫awk腳本來讀取文件,識別列組,將它們寫出到兩個單獨的文件,並構建連接命令行。 – Max

回答

1

的代碼假設表是由空行分隔:

awk -F', *' 'END { 
    for (i = 0; ++i <= c;) 
    printf "%s", (cols[i] (i < c ? OFS : RS)) 
    for (i = 0; ++i <= n;) 
    for (j = 0; ++j <= c;) 
     printf "%s", (vals[i, cols[j]] (j < c ? OFS : RS))  
    } 
!NF { 
    fnr = NR + 1; next 
    } 
NR == 1 || NR == fnr { 
for (i = 0; ++i <= NF;) { 
    _[$i]++ || cols[++c] = $i 
    idx[i] = $i 
    } 
    next 
    } 
{ 
    ++n; for (i = 0; ++i <= NF;) 
     vals[n, idx[i]] = $i 
    }' OFS=', ' tables 

如果你有單獨的文件中的表:

awk -F', *' 'END { 
    for (i = 0; ++i <= c;) 
    printf "%s", (cols[i] (i < c ? OFS : RS)) 
    for (i = 0; ++i <= n;) 
    for (j = 0; ++j <= c;) 
     printf "%s", (vals[i, cols[j]] (j < c ? OFS : RS))  
    } 
FNR == 1 { 
for (i = 0; ++i <= NF;) { 
    _[$i]++ || cols[++c] = $i 
    idx[i] = $i 
    } 
    next 
    } 
{ 
    ++n; for (i = 0; ++i <= NF;) 
     vals[n, idx[i]] = $i 
    }' OFS=', ' file1 file2 [.. filen] 
2

試試這個:

代碼:

$ cat s.awk 
NR==FNR{ 
    if (match($1, /^col/)) 
     maxIndex=(substr($NF,4,1)>maxIndex)?substr($NF,4,1):maxColumn 
    next 
} 

FNR==1{ 
    for (i=1;i<=maxIndex;i++) 
     header=(i==maxIndex)?header "col"i:header "col" i ", " 
    print header 
} 

/^col[1-9]/{ 
    for (i in places) 
     delete places[i] 
    for (i=1;i<=NF;i++){ 
     n=substr($i,4,1) 
     places[n]=i 
    } 
} 

/^[0-9]/{ 
    s="" 
    for (i=1;i<=maxIndex;i++) 
     s=(i in places)? s $places[i] " " : s ", " 
    print s 
} 

調用具有:

awk -f s.awk file file | column -t 

輸出:

col1, col2, col3, col4, col5 
1,  2,  3,  4  , 
5,  6,  7,  8  , 
,  10, 11, ,  12 
,  13, 14, ,  15 

HTH克里斯

+0

如果只有我的列標題被很好地命名,這將工作得很好。我不應該按照我的方式命名它們,因爲這使得它們的名字似乎有了一個模式。任何想法,如果列名非常隨機怎麼辦? – Daniel

+0

請給我們具體的例子,你有什麼和你想要什麼。幾乎是隨機的,幾乎和所有東西一樣具體。 – Chris

+0

或者你可以預處理你的數據。在第一步中,創建一個從列名到「colX」風格名稱的地圖。然後使用awk/sed重命名列名,最後運行我的腳本。 – Chris

1

這是一個perl perl解決方案。它假定文件中的每個表格之間至少有一個空白行。

perl -00 -ne ' 
    BEGIN { 
     %column2idx =(); 
     @idx2column =(); 
     $lineno = 0; 
     @lines =(); 
    } 

    chomp; 
    @rows = split /\n/; 

    @field_map =(); 
    @F = split /, /, $rows[0]; 
    for ($i=0; $i < @F; $i++) { 
     if (not exists $column2idx{$F[$i]}) { 
      $idx = @idx2column; 
      $column2idx{$F[$i]} = $idx; 
      $idx2column[$idx] = $F[$i]; 
     } 
     $field_map[$i] = $column2idx{$F[$i]}; 
    } 

    for ($i=1; $i < @rows; $i++) { 
     @{$lines[$lineno]} =(); 
     @F = split /, /, $rows[$i]; 
     for ($j=0; $j < @F; $j++) { 
      $lines[$lineno][$field_map[$j]] = $F[$j]; 
     } 
     $lineno++; 
    } 

    END { 
     $ncols = @idx2column; 
     print join(", ", @idx2column), "\n"; 

     foreach $row (@lines) { 
      @row =(); 
      for ($i=0; $i < $ncols; $i++) { 
       push @row, $row->[$i]; 
      } 
      print join(", ", @row), "\n"; 
     } 
    } 
' tables | column -t 

輸出

col1, col2, col3, col4, col5 
1,  2,  3,  4, 
5,  6,  7,  8, 
,  10, 11, ,  12 
,  13, 14, ,  15 
+1

這對於以「col2,col3,col5」開頭,接着是「col1,col2,col3,col4」的文件不起作用。 (這個例子的反面) – Chris

+1

我假定列標題可以是任意的任意名稱,比如「first,last,phone,addr,...」並且不一定是數字。 –

+0

順便說一句,它確實有效,輸出中的列是:「col2,col3,col5,col1,col4」 –