2017-09-04 73 views
1

我是新來bash和有以下要求:慶典 - 基於價值選擇列

我有如下文件:

col1,col2,col3....col25 
s1,s2,s2..........s1 
col1,col2,col3....col25 
s3,s2,s2..........s2 

如果你注意到這些列的值可以是3種類型只有:S1,S2,S3

我可以提取給定的文件,給了我最後2rows:

col1,col2,col3....col25 
s3,s1,s2..........s2 

我想進一步解析上面的行,以便我只獲得具有say值的列s1。

所需的輸出: 說COL3,col25與s2值的唯一列,然後說逗號分隔值也蠻好例如:

col3,col25 

是否有人可以幫忙嗎?

P.S.我發現很多基於say 2nd(固定)列的值解析文件的例子,但是當列號不固定時,我們該怎麼做? 經過網址: awk one liner select only rows based on value of a column

+5

顯示應該如何看最後的結果 – RomanPerekhrest

+0

說COL2,COL4與值S1的唯一列,然後說一個逗號分隔值也未嘗前:col2,col4 – learner

+0

@learner,用你想要的結果集更新你的問題;在這種情況下,您可能想要更新您的示例數據,因爲沒有任何內容(此刻)顯示col4的內容(當然,我們可以想象樣本數據的樣子,但在您的問題中顯示它不會有什麼傷害) – markp

回答

2

假設:

  • 有2條輸入線
  • 每個輸入行具有相同數量的用逗號分隔的

我們還可以使用兩個陣列收集的輸入數據,確保使用相同的數組索引。一旦數據被加載到數組中,我們循環遍歷數組尋找我們的值匹配。

$ cat col.awk 
    /col1/ { for (i=1; i<=NF; i++) { arr_c[i]=$i } ; n=NF } 
! /col1/ { for (i=1; i<=NF; i++) { arr_s[i]=$i }  } 
END { 
sep="" 
for (i=1; i<=n; i++) 
    { if (arr_s[i]==smatch) 
     { printf "%s%s" ,sep,arr_c[i] 
      sep=", " 
     } 
    } 
} 
  • /col1/:對包含col1,存儲在陣列中的字段arr_c
  • n=NF行:抓住我們最大數組索引值(NF =字段數)
  • ! /col1/:對於行不包含col1,存儲數組中的字段arr_s
  • END ...:一旦數組加載就執行
  • sep="":設置我們的初始輸出分離器爲空字符串
  • for (...):通過我們的數組索引環路(1到n)
  • if (arr_s[i]==smatch):如果S數組值我們的輸入參數匹配(SMATCH - 見下例) ,然後...
  • printf "%s%s",sep,arr_c[i]:printf的我們sep和對應的C數組的項目,然後...
  • sep=", ":設置我們分隔在循環
下一場比賽210

我們使用printf,因爲沒有指定'\ n'(一個新行),所有輸出都轉到一行。

實施例:

$ cat col.out 
col1,col2,col3,col4,col5 
s3,s1,s2,s1,s3 
$ awk -F, -f col.awk smatch=s1 col.out                       
col2, col4 
  • -F,:定義輸入字段分隔符爲逗號
  • 這裏我們在我們的搜索圖案s1通過在名爲smatch數組變量,其在awk代碼中引用(請參見上面的列表)

如果你想在comman上做所有的事情d線:

$ awk -F, ' 
    /col1/ { for (i=1; i<=NF; i++) { arr_c[i]=$i } ; n=NF } 
! /col1/ { for (i=1; i<=NF; i++) { arr_s[i]=$i }  } 
END { 
sep="" 
for (i=1; i<=n; i++) 
    { if (arr_s[i]==smatch) 
     { printf "%s%s" ,sep,arr_c[i] 
      sep=", " 
     } 
    } 
} 
' smatch=s1 col.out 
col2, col4 

或摺疊的END塊一行:

awk -F, ' 
    /col1/ { for (i=1; i<=NF; i++) { arr_c[i]=$i } ; n=NF } 
! /col1/ { for (i=1; i<=NF; i++) { arr_s[i]=$i }  } 
END { sep="" ; for (i=1; i<=n; i++) { if (arr_s[i]==smatch) { printf "%s%s" ,sep,arr_c[i] ; sep=", " } } } 
' smatch=s1 col.out 
col2, col4 
+0

令人驚歎的答案。它不僅工作,詳細的解釋是非常有用的。真是一個非凡的答案。非常感謝。 – learner

1

我不是awk那麼好,但這裏的東西,似乎工作,僅輸出列名,其對應的值是s1

#<yourTwoLines> | 
    tac | 
    awk -F ',' 'NR == 1 { for (f=1; f<=NF; f++) { relevant[f]= ($f == "s1") } }; 
       NR == 2 { for (f=1; f<=NF; f++) { if(relevant[f]) print($f) } }' 

它工作在方式如下:

  1. 扭轉線訂購帶有tac,因此值(標準)的報頭之前被處理(瓦特我們將根據標準打印)。

  2. 處理以陣列與awk處理第二行(現在的標題)時哪些是s1

  3. awk的第一行(現在值),存儲時,打印那些誰對應於s1值感謝以前填充的數組。

+0

謝謝,會進一步檢查這個答案。 – learner

0

比方說,你有這樣的:

cat file 
col1,col2,col3,..,col25 
s3,s1,s2,........,s2 

然後你就可以使用這個awk

awk -F, -v val='s2' '{ 
    s=""; 
    for (i=1; i<=NF; i++) 
    if (NR==1) 
     hdr[i]=$i 
    else if ($i==val) 
     s=s hdr[i] FS; 
    if (s) { 
    sub(/,$/, "", s); 
    print s 
    } 
}' file 

col3,col25 
+0

感謝您的回覆。 – learner

1

解決方案awk在分析每行2行後打印結果行。

$ cat tst.awk 
BEGIN {FS=","; p=0} 
/s1|s2|s3/ { 
    for (i=1; i<NF; i++) { 
     if ($i=="s2") str = sprintf("%s%s", str?str ", ":str, c[i]) 
    }; 
    p=1 
} 
!p { for (i=1; i<NF; i++) { c[i] = $i } } 
p { print str; p=0; str="" } 

基本原理:建立結果字符串str當您循環訪問值行時。

  • 每當輸入包含S1,S2或S3,循環通過的元件和 - 如果value == s2 - , - 具有索引i到resultstring str添加柱;設置打印VAR p爲1
  • 如果p = 0積聚列陣列
  • 如果p = 1打印resultstring str

隨着輸入:

$ cat input.txt 
col1,col2,col3,col4,col5 
s1,s2,s2,s3,s1 
col1,col2,col3,col4,col5 
s1,s1,s2,s3,s3 
col1,col2,col3,col4,col5 
s1,s1,s1,s3,s3 
col1,col2,col3,col4,col5 
s1,s1,s2,s3,s3 

結果是:

$ awk -f tst.awk input.txt 
col2, col3 
col3 

col3 

注意空第三行:沒有s2的那個。

+0

感謝您的回覆。 – learner

0

如果返回的列的順序是不是一個問題

awk -F"," 'NR==1{for(i=1;i<=NF;i++){a[i]=$i};next}{for(i=1;i<=NF;i++){if($i=="s2")b[i]=$i}}END{for(i in b) m=m a[i]","; gsub(/,$/,"", m); print m }'