【问题标题】:Break lines at specified points with awk用 awk 在指定点换行
【发布时间】:2017-07-09 02:15:23
【问题描述】:

我有一个包含多行的文件,格式如下:

name1    a1    b3    c6    a3    b4    c9
name2    a7    b8    c7    a9    b10   c13
name3    a12   b9    c8
name4    a4    b34   c19   a7    b2    c10    a3    b5    c67

我需要在字母重复后换行(即在每个 a、b、c 之后),但保留原始名称(字段 1):

name1    a1    b3    c6    
name1    a3    b4    c9
name2    a7    b8    c7    
name2    a9    b10   c13
name3    a12   b9    c8
name4    a4    b34   c19   
name4    a7    b2    c10    
name4    a3    b5    c67

我尝试了一些类似的东西:

awk -F"\t" '{ for (i=2;i<=NF;i++) print $1"\t"$i }' file

但是i++ 包含每个字段,有没有办法对它们进行分组?

谢谢。

【问题讨论】:

  • 字母会乱序吗? c2a3b1?
  • @Mark Setchell 是的,他们可以
  • 他们会一直重复还是会有不重复的行?
  • 我们可以得到z1 q2 a1 d7 r0 z2 吗?
  • @starter5: 请您也试试我提供的解决方案如下一次吗?

标签: awk split


【解决方案1】:

@starter5:试试:

awk 'BEGIN{V["a"];V["b"];V["c"]} /name/{R=$0;next} {Q=$0;gsub(/[[:digit:]]/,"",Q)} (Q in V){if(!W[Q]++){A++}} $0{if(A==1 && $0 && R){$0=R OFS $0};printf("%s %s",$0,(A==3?"\n":OFS));;if(A==3){A="";delete W}}' RS='[ +|\n]'  Input_file

这里也是NON-one liner形式的解决方案。

awk 'BEGIN{
                V["a"];
                V["b"];
                V["c"]
          }
                /name/{
                        R=$0;
                        next
                      }
          {
                Q=$0;
                gsub(/[[:digit:]]/,"",Q)
          }
                (Q in V){
                                if(!W[Q]++){
                                                A++
                                           }
                        }
                $0      {
                                if(A==1 && $0 && R){
                                                        $0=R OFS $0
                                                   };
                                printf("%s %s",$0,(A==3?"\n":OFS));;
                                if(A==3)           {
                                                        A="";
                                                        delete W
                                                   }
                        }
    ' RS='[ +|\n]'    Input_file

假设我们有以下 Input_file(我在其中更改了最后一行)来测试 a、b、c 是否没有按顺序出现,所以在找到其中三个之前它不会断行,看看它并那就告诉我吧。

cat  Input_file
name1    a1    b3    c6    a3    b4    c9
name2    a7    b8    c7    a9    b10   c13
name3    a12   b9    c8
name4    a4    b34   a19   a7    b2    c10    a3    b5    c67

输出如下。

name1 a1  b3  c6
name1 a3  b4  c9
name2 a7  b8  c7
name2 a9  b10  c13
name3 a12  b9  c8
name4 a4  b34  a19  a7  b2  c10
name4 a3  b5  c67

【讨论】:

  • 您显示的 输出 与 OP 的输出或我得到的不匹配,与 OP 相同,运行您的 awk 程序我>。应该有三个单独的 name4 行,而您只看到两个。
  • @user3439894:请与 OP 一起清楚地阅读我的声明,所以我在 Input_file 中进行了更改,并没有按顺序制作所有 a、b、c,所以它打印了这些行,直到找到所有 3 a,b,c 在行中的匹配。如果我们使用发布的 OP 之类的确切文件,它也应该可以使用。我希望这会有所帮助。
【解决方案2】:
{                                   # for any record
    printf $1                       # print name
    c=substr($2,1,1);               # first letter of group
    printf OFS $2                   # first part of first group
    for(i=3; i<=NF; i++) {          # for all the rest fields
        if(index($i,c) != 1)        # if next group has not started
            printf OFS $i           # print this part on same line
        else                        # otherwise
            printf ORS $1 OFS $i    # print name and this part on next line
    }                               # done for all fields
    printf ORS                      # move to next line
}                                   # done for this record

如果某个字母在组内重复,这将不起作用。例如,它不适用于存在 a b a c 组的 a3 b5 a4 c6 a5 b6 a0 b9

这可以像这样运行:

awk '{ printf $1; c=substr($2,1,1); printf OFS $2; for(i=3;i<=NF;i++) if(index($i,c)!=1) printf OFS $i; else printf ORS $1 OFS $i; printf ORS}' file

【讨论】:

    【解决方案3】:

    我需要在字母重复后换行(即在每个 a,b,c),但保留原始名称(字段 1):

    输入

    $ cat file
    name1    a1    b3    c6    a3    b4    c9
    name2    a7    b8    c7    a9    b10   c13
    name3    a12   b9    c8
    name4    a4    b34   c19   a7    b2    c10    a3    b5    c67
    

    输出

    $ awk 'function _p(){print $1,s; s=""; split("",p)}{for(i=2; i<=NF; i++){ c=substr($i,1,1);if(c in p)_p(); s = (s?s OFS:"") $i; p[c] }_p()}' file
    name1 a1 b3 c6
    name1 a3 b4 c9
    name2 a7 b8 c7
    name2 a9 b10 c13
    name3 a12 b9 c8
    name4 a4 b34 c19
    name4 a7 b2 c10
    name4 a3 b5 c67
    

    可读性更好的版本

    awk '
       function _p()
       {
                  print $1,s;
                  s=""; 
                  split("",p)
       }
       {
          for(i=2; i<=NF; i++)
          { 
                  c=substr($i,1,1); 
                  if(c in p)_p();
                  s = (s?s OFS:"") $i; 
                  p[c] 
          }
          _p()
       }
        ' file
    

    $ awk 'function _p(){print $1,s; s=p=""}{for(i=2; i<=NF; i++){ c=substr($i,1,1); if(c==p)_p(); s = (s?s OFS:"") $i; if(!p)p=c }_p()}' file
    name1 a1 b3 c6
    name1 a3 b4 c9
    name2 a7 b8 c7
    name2 a9 b10 c13
    name3 a12 b9 c8
    name4 a4 b34 c19
    name4 a7 b2 c10
    name4 a3 b5 c67
    

    可读性更好的版本

    awk '
         function _p()
         {
            print $1,s; 
            s=p=""
         }
         {
            for(i=2; i<=NF; i++)
            { 
                c=substr($i,1,1); 
                if(c==p)_p(); 
                s = (s?s OFS:"") $i; 
                if(!p)p=c 
            }
              _p()
         }' file
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-10
      • 1970-01-01
      • 2014-03-27
      • 2014-08-25
      • 1970-01-01
      • 1970-01-01
      • 2013-08-29
      • 2016-10-29
      相关资源
      最近更新 更多