使用awk将匹配标题字符串的列移动到文件末尾

时间:2017-10-26 18:44:25

标签: linux awk

我有一个包含2000多列的分隔文件。我想通过将匹配特定模式的列移动到文件末尾来重新排列列(以及此标题下的所有行)。

我的意见:

col1:aa01 col2:aa02 col3:nn08 col4:aa03 col5:nn08 col6:aa04
value1    value2    value3    value4    value5    value6

希望以' nn08'搬到了最后:

col1:aa01 col2:aa02 col4:aa03 col6:aa04 col3:nn08 col5:nn08
value1    value2    value4    value6    value3    value5 

这是我到目前为止从论坛收集的内容,但显然它不起作用:

awk 'BEGIN{FS=OFS="\t"} {a ~ /nn08/; for (i=2;i<NF; i++) $i=$(i+1); $NF=a; print}' in >out

非常感谢任何帮助。谢谢。

3 个答案:

答案 0 :(得分:0)

使用 awk 单行

$awk 'FNR==1{ for(i=1; i<=NF; i++) if($i~/nn08/) a[i]++; } {for(i in a){str=str $i FS; $i=""} $0=$0 FS str; $1=$1; str=""}1' file

col1:aa01 col2:aa02  col4:aa03  col6:aa04 col3:nn08 col5:nn08

FNR==1{for(i=1; i<=NF; i++) if($i~/nn08/) a[i]++; }:对于第一行,即标题,遍历每个字段,if($i~/nn08/)为真,然后设置a[i]的值。 a是一个关联数组,其中i将成为键,值将递增(如果键不存在,则最初为0) 例如。第三列a[3]=1和类似a[5]=1第五列。目标是将列号存储为a中需要移位的键。

{for(i in a){str=str $i FS; $i=""} $0=$0 FS str; $1=$1; str=""}1 接下来,根据i中存储的每个键/列字段编号a将列值$i附加到结束str变量并将column设置为{{1}即null。循环后,将$i=""附加到整个记录str

注意:$0强制awk改造整个记录,删除在我们通过$1=$1截断字段时创建的额外FS(空格)。

答案 1 :(得分:0)

一衬垫:

awk '{t = "";for(i=1; i<=NF; i++){if(FNR==1 && $i ~ /:nn08$/){h[i] = $i}if( i in h){t = ( t ? t OFS :"" ) $i;continue;}printf("%s%s",$i, OFS)}print t}' infile

更好的可读性:

awk '
    {
      t = "";
      for(i=1; i<=NF; i++)
      {

          # store column index in array h
          if(FNR==1 && $i ~ /:nn08$/){
                   h[i] = $i
          }

          # if column to be skipped then
          if( i in h)
          {
             # concatenate variable
             t = ( t ? t OFS :"" ) $i;

             # continue
             continue;      
          }

          # if ok, then print such column
          printf("%s%s",$i, OFS)
      }

      # print rest of them saved in variable
      print t
    }
    ' infile

输入:

$ cat infile
col1:aa01 col2:aa02 col3:nn08 col4:aa03 col5:nn08 col6:aa04
value1    value2    value3    value4    value5    value6

输出:

$ awk '{t = "";for(i=1; i<=NF; i++){if(FNR==1 && $i ~ /:nn08$/){h[i] = $i}if( i in h){t = ( t ? t OFS :"" ) $i;continue;}printf("%s%s",$i, OFS)}print t}' infile
col1:aa01 col2:aa02 col4:aa03 col6:aa04 col3:nn08 col5:nn08
value1 value2 value4 value6 value3 value5

答案 2 :(得分:0)

这是另一个

$ awk 'NR==1 {for(i=1;i<=NF;i++) if($i~/:nn08$/) p[i]} 
             {for(i=1;i<=NF;i++) if(!(i in p)) printf "%s",$i FS; 
              for(i in p) printf "%s",$i FS;
              print ""}' file

它可以提高效率,但也许就足够了。