【问题标题】:Awk for loop not searching all fieldsawk for 循环不搜索所有字段
【发布时间】:2020-11-10 01:48:29
【问题描述】:

我正在尝试

  1. 打印前 3 列
  2. 找到所有带有“Eury_gr1_”的字段并将它们打印到第 4 列
  3. 如果整行中没有“Eury_gr1_”,则在第 4 列打印 0。

输入如下所示,名为“final_pcs_mod_test.csv”:

PC_00001,143,143.0,Eury_gr2_(111),Eury_gr5_(19),Unk_unclust_(1),Eury_gr1_(6),MAV_eury_(6)
PC_00004,137,137.0,Eury_gr6_(20),Eury_gr11_(24),Eury_gr14_(24),Eury_gr8_(8),Eury_gr12_(13)
PC_00027,109,109.0,Eury_gr1_(80),MAV_eury_(8)

所需的输出将如下所示,名为“eury1”:

PC_00001,143,143.0,Eury_gr1_(6)
PC_00004,137,137.0,0
PC_00027,109,109.0,Eury_gr1_(80)

我使用的命令是:

awk 'BEGIN {FS=","};{for(i=4;i<=NF;i++){if($i~/^Eury_gr1_/){a=$i} else {a="0"}} print $1,$2,$3,a}' final_pcs_mod_test.csv > eury1

实际输出为:

PC_00001,143,143.0,0
PC_00004,137,137.0,0
PC_00027,109,109.0,Eury_gr1_(80)

如您所见,第一行缺少“Eury_gr1_”条目。看起来代码只在第一个指定的列中查找,而不是按照我的需要搜索所有列。我一直在搞乱for(i=4;i&lt;=4;i++) 等......但到目前为止似乎无法让它在输入的最后一列中找到条目。整个输入文件最多有 17 列。我做错了什么?

【问题讨论】:

    标签: for-loop awk


    【解决方案1】:

    您能否尝试在 GNU awk 中使用所示示例进行跟踪、编写和测试。输出将与显示的示例相同。

    awk '
    BEGIN{
      FS=OFS=","
    }
    {
      for(i=4;i<=NF;i++){
        if($i~/Eury_gr1_\([0-9]+\)/){
            found=(found?found OFS:"")$i
         }
      }
      if(found==""){ $4="0"   }
      else         { $4=found }
      print $1,$2,$3,$4
      found=""
    }' Input_file
    

    awk '
    BEGIN{
      FS=OFS=","
    }
    {
      for(i=1;i<=NF;i++){
        if(i<=3){
          val1=(val1?val1 OFS:"")$i
        }
        else if(i>3){
          if($i~/Eury_gr1_\([0-9]+\)/){
            found=(found?found OFS:"")$i
          }
        }
      }
      if(found==""){ $4="0"   }
      else         { $4=found }
      print val1,$4
      found=val1=""
    }' Input_file
    

    说明:为上述添加详细说明。

    awk '                                    ##Starting awk program from here.
    BEGIN{                                   ##Starting BEGIN section from here of this program.
      FS=OFS=","                             ##Setting field separator and output field separator to comma here.
    }
    {
      for(i=1;i<=NF;i++){                    ##Traversing through all the fields of current line here.
        if(i<=3){                            ##Checking condition if field number of lesser than or equal to 3 then do following.
          val1=(val1?val1 OFS:"")$i          ##Creating val1 and keep adding values there.
        }
        else if(i>3){                        ##else if field number is greater than 3 then do following.
          if($i~/Eury_gr1_\([0-9]+\)/){      ##Checking if current field is Eury_gr1_(digits) then do following.
            found=(found?found OFS:"")$i     ##Creating variable found and keep adding values there.
          }
        }
      }
      if(found==""){ $4="0"   }              ##Checking condition if found is NULL then make 4th field as zero.
      else         { $4=found }              ##else set found value to 4th field here.
      print val1,$4                          ##Printing val1 and 4th field here.
      found=val1=""                          ##Nullifying val1 and found here.
    }' Input_file                            ##Mentioning Input_file name here.
    

    OP 的尝试修复: 根据 OP 的 cmets 在此处修复 OP 的尝试。但这只会匹配每行出现 1 次的 Eury_gr1,要查找所有出现次数,请参考我上面的解决方案。

    awk '
    BEGIN{
      FS=","
    }
    {
      for(i=4;i<=NF;i++){
        if($i~/^Eury_gr1_\([0-9]+\)$/){ a1 }
      }
      print $1,$2,$3,a1
      a1=""
    }' Input_file
    

    【讨论】:

    • 啊!它像梦一样工作!谢谢!您是否介意添加一点解释,因为我正处于 bash 的学习阶段,并且可以使用指针来说明我做错了什么以及您如何解决它?
    • @Dvik,欢迎您。我也添加了您的尝试修复。您尝试的问题是,您在 if 和 else 条件中使用了相同的变量,因此它永远无法捕获匹配的值,因为每次出现不匹配的字段时,它都会覆盖其中的匹配值。干杯。
    • 完美。完全有道理,我现在明白了。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-08
    • 2013-08-28
    • 2020-11-07
    • 2015-01-25
    • 1970-01-01
    相关资源
    最近更新 更多