2017-09-04 57 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 }'