通过使用AWK匹配、重命名和赋值来提取列

通过使用AWK匹配、重命名和赋值来提取列,awk,aggregate,Awk,Aggregate,我有一个以制表符分隔的csv文件,其中包含对象长度的摘要统计信息: sampled. objs. obj. min. len. obj. mean. len. obj. max. len. obj. std. 50 22 60 95 5 我希望通过搜索匹配的列标题obj来获得关于最小和最大长度的信息。莱恩小姐。和obj。马克斯·莱恩。。然后我想创建一个新的csv文件,用逗号分隔,并用新的列标题来获得结果 object_minimum,object_maximum 22,95 我

我有一个以制表符分隔的csv文件,其中包含对象长度的摘要统计信息:

sampled. objs.  obj. min. len.  obj. mean. len. obj. max. len.  obj. std.
50  22  60  95  5
我希望通过搜索匹配的列标题obj来获得关于最小和最大长度的信息。莱恩小姐。和obj。马克斯·莱恩。。然后我想创建一个新的csv文件,用逗号分隔,并用新的列标题来获得结果

object_minimum,object_maximum
22,95
我首先打印新的标题。然后我尝试检索匹配的索引,然后使用这些索引从第二行提取:

#!/bin/awk -f

BEGIN {
    cols="object_minimum:object_maximum"
    FS="\t"
    RS="\n"
    col_count=split(cols, col_arr, ":");
    for(i=1; i<=col_count; i++) printf col_arr[i] ((i==col_count) ? "\n" : ",");
}
{
    for (i=1; i<=NF; i++) {
        if(index($i,"obj. min. len.") !=0) {
        data["object_minimum"]=i;
        }
        if(index($i,"obj. max. len.") !=0) {
        data["object_maximum"]=i;
        }  
    }
}
END NR==1 {
    for (j=1; j<=col_count; j++) printf NF==data[j] ((i==col_count) ? "\n" : ",");
}

请您尝试以下内容,完全基于您展示的样本,用GNU awk编写和测试。创建了一个名为sep=的awk变量,也可以根据需要进行更改

awk -v sep="###" '
BEGIN{
  OFS=","
}
FNR==1{
  while(match($0,/ +obj\./)){
    val=substr($0,RSTART,RLENGTH)
    sub(/^ +/,"",val)
    line=(line?line:"")substr($0,1,RSTART-1)sep val
    $0=substr($0,RSTART+RLENGTH)
  }
  if(substr($0,RSTART+RLENGTH)!=""){
    line=line substr($0,RSTART+RLENGTH)
  }
  num=split(line,arr,sep)
  for(i=1;i<=num;i++){
    if(arr[i]=="obj. min. len."){ min=i }
    if(arr[i]=="obj. max. len."){ max=i }
  }
  print "object_minimum,object_maximum"
  next
}
{
  print $min,$max
}
'  Input_file

逻辑解释:处理输入文件的第一行。然后使用awk的match函数查找匹配项+obj\。在当前行中。在本例中,创建一个具有匹配值和匹配前值的变量。完成对特定正则表达式的所有搜索后,即会找到所有匹配正则表达式。然后用分隔符拆分新创建的变量,假设它们不存在于您的输入文件中,则使用分隔符将它们转换为数组中的其他值。最后检查该数组的所有元素,并在列为obj时设置条件。莱恩小姐。然后将最小变量值设置为特定的索引号,该索引号实际上是其余行的字段号,若值为obj。马克斯·莱恩。然后设置max变量。在处理完第一行后,只需通过$min、$max.打印相应的字段。

您是否可以尝试以下内容,完全基于所显示的样本,使用GNU awk编写和测试。创建了一个名为sep=的awk变量,也可以根据需要进行更改

awk -v sep="###" '
BEGIN{
  OFS=","
}
FNR==1{
  while(match($0,/ +obj\./)){
    val=substr($0,RSTART,RLENGTH)
    sub(/^ +/,"",val)
    line=(line?line:"")substr($0,1,RSTART-1)sep val
    $0=substr($0,RSTART+RLENGTH)
  }
  if(substr($0,RSTART+RLENGTH)!=""){
    line=line substr($0,RSTART+RLENGTH)
  }
  num=split(line,arr,sep)
  for(i=1;i<=num;i++){
    if(arr[i]=="obj. min. len."){ min=i }
    if(arr[i]=="obj. max. len."){ max=i }
  }
  print "object_minimum,object_maximum"
  next
}
{
  print $min,$max
}
'  Input_file

逻辑解释:处理输入文件的第一行。然后使用awk的match函数查找匹配项+obj\。在当前行中。在本例中,创建一个具有匹配值和匹配前值的变量。完成对特定正则表达式的所有搜索后,即会找到所有匹配正则表达式。然后用分隔符拆分新创建的变量,假设它们不存在于您的输入文件中,则使用分隔符将它们转换为数组中的其他值。最后检查该数组的所有元素,并在列为obj时设置条件。莱恩小姐。然后将最小变量值设置为特定的索引号,该索引号实际上是其余行的字段号,若值为obj。马克斯·莱恩。然后设置max变量。在处理完第一行后,只需通过执行$min、$max.打印相应的字段。

这里是一个工作原型,添加格式和错误检查

$ awk -F'\t' -v OFS=, '
       NR==1 {for(i=1;i<=NF;i++) 
                if($i=="obj. min. len.") min=i; 
                else if($i=="obj. max. len.") max=i; 
              print "min","max"}
       NR==2 {print $min,$max; exit}' file

min,max
22,95

这里是一个工作原型,添加格式和错误检查

$ awk -F'\t' -v OFS=, '
       NR==1 {for(i=1;i<=NF;i++) 
                if($i=="obj. min. len.") min=i; 
                else if($i=="obj. max. len.") max=i; 
              print "min","max"}
       NR==2 {print $min,$max; exit}' file

min,max
22,95
使用awk:

输出:

22,95 资料来源:

请参阅:

带awk:

输出:

22,95 资料来源:


请参阅:

标题行中的列名是如何相互分隔的?看起来好像名字之间有两个空格,名字中有一个空格?那太恶心了。数据行中的列是否也用双空格分隔?您正在使用哪个版本的awk?您计划如何识别必须提取的输入列名和必须生成的输出列名,以及计划如何指定输出列的显示顺序?隐马尔可夫模型;您显示的awk脚本表明字段分隔符是选项卡-这更容易。请确认。设置OFS=,可能会节省一些焦虑-输出字段分隔符。同样,它可能没有任何好处,因为您可能需要在一行的多个printf调用中写出位和段。它是以制表符分隔的,标题名中有空格,我同意这不好,这就是为什么它们需要更改的原因。列的顺序和新列的名称由我如何指定cols给出。我首先以我想要的逗号分隔格式打印列名。然后我需要提取并打印下面的值,标题行中的列名是如何相互分离的?看起来好像名字之间有两个空格,名字中有一个空格?那太恶心了。数据行中的列是否也用双空格分隔?您正在使用哪个版本的awk?您计划如何识别必须提取的输入列名和必须生成的输出列名,以及计划如何指定输出列的显示顺序?隐马尔可夫模型;您显示的awk脚本表明字段分隔符是选项卡-这更容易。请确认。设置OFS=,可能会节省一些焦虑-输出字段分隔符。同样,它可能没有任何好处,因为您可能需要在一行的多个printf调用中写出位和段。它是以制表符分隔的,标题名中有空格,我同意这不好,这就是为什么它们需要更改的原因。列和na的顺序
新列的mes由我如何指定COL给出。我首先以我想要的逗号分隔格式打印列名。然后我需要提取并打印下面的值,显示的代码的哪个方面需要GNU Awk,而不是任何其他变量?它实际上并不打印映射的标题,但在其他方面却非常优雅。@JonathanLeffler:我通常只使用GNU awk进行测试。很公平-我不认为其中有任何代码依赖于awk的GNU特性。这是一个非常好、优雅的解决方案。@JonathanLeffler:谢谢你的提示。我已经更新了我的答案。所示代码的哪个方面需要GNU Awk,而不是任何其他变体?它实际上并不打印映射的标题,但在其他方面却非常优雅。@JonathanLeffler:我通常只使用GNU awk进行测试。很公平-我不认为其中有任何代码依赖于awk的GNU特性。这是一个非常好、优雅的解决方案。@JonathanLeffler:谢谢你的提示。我已经更新了我的答案。