基于星号(*)加入行

时间:2017-09-22 11:29:39

标签: unix awk sed gawk

我的文本文件中包含几行以" i"一些与" u>我"和其他作为"?"这些行下方总共有2行,我想加入这两行(追加),其中包含任意位置的行""。

尝试了awk,sed但没有获得可以解决此问题的确切字符串。

档案数据: -

*i    80.95.226.72/29                                    n/a         None

    193.105.101.26                                     None        -
    28834 64690

*?    85.118.193.0/25                                    n/a         None

    193.105.101.26                                     None        -
    28834 64814

u*>i  213.226.55.0/24                                    n/a         None

    193.105.101.27                                     None        -
    28834 64757

*i    80.65.79.160/27                                    n/a         None
    193.105.101.26                                     None        -
    28834 9146

预期产出: -

*i,80.95.226.72/29,n/a,None,193.105.101.26 ,None,-,28834,64690
*?,85.118.193.0/25,n/a,None,193.105.101.26 ,None,-,28834,64814
u*>i,213.226.55.0/24,n/a,None193.105.101.27 ,None,-,28834,9146

3 个答案:

答案 0 :(得分:0)

awk 解决方案,无论任何行中的字段数量是多少,都是:

$ cat tst.awk
BEGIN{OFS=","}
NF && p && !/\*/ { p = p OFS coalesce(); next}
/\*/{ if (p) print p; p=coalesce()}0
function coalesce(){
   s=""
   for (i=1;i<=NF;i++) s=s (i==NF ? $i : $i OFS)
   return s
}

<强>解释

BEGIN{OFS=","}                         # set Output Field Separator to ","
NF && p && !/\*/ {                     # if nr of fields > 0, not containing 
                                       # '*' and p is set
    p = p OFS coalesce(); next         # add formatted $0 to p
} 
/\*/{                                  # if $0 contains '*'
    if (p) print p;                    #   if p then print it
    p=coalesce()                       #   initialize p
}0                                     # ignore rest of lines
function coalesce(){
   s=""
   for (i=1;i<=NF;i++) s=s (i==NF ? $i : $i OFS)
   return s
}

<强>测试

$ awk -f tst.awk input.txt
*i,80.95.226.72/29,n/a,None,193.105.101.26,None,-,28834,64690
*?,85.118.193.0/25,n/a,None,193.105.101.26,None,-,28834,64814
u*>i,213.226.55.0/24,n/a,None,193.105.101.27,None,-,28834,64757

oneliner

$ awk -v OFS=, '$0 && p && !/\*/ { p = p OFS coalesce(); next}/\*/{ if (p) print p; p=coalesce()}0;function coalesce(){s="";for (i=1;i<=NF;i++) s=s (i==NF ? $i : $i OFS);return s}' input.txt

答案 1 :(得分:0)

单行 awk

$ awk -v OFS=, 'NF{$1=$1; s=(s?s OFS:"") $0}NF==2 && s{print s; s=""}' infile

要解决您的帖子标题:

awk -v OFS=, -v n=2 'NF{$1=$1}/\*/{s=$0;next}s && NF && n>=c++{s = s OFS $0}c==n{print s; s=c=""}' infile

更好的可读性:

awk -v OFS=, -v n=2 '
                     NF{ 
                          $1 = $1 
                       }
                   /\*/{
                          s=$0
                          next 
                       }
      s && NF && n>=c++{
                           s = s OFS $0
                       }
                   c==n{
                           print s 
                           s = c = ""
                       }
                    ' infile

<强>解释

  
      
  • NF{ $1 = $1 }
  •   
     

如果行/记录/行至少有一个字段(NF没有字段。)   记录),然后重新编译记录,因为当你$1=$1(或任何   对字段的其他分配)它导致记录重新编译$0   每FS替换为OFS重建。

     
      
  • /\*/{ s = $0; next }
  •   
     

如果行包含*,则为变量s分配当前值   记录/行/行,然后转到下一行。

     
      
  • s && NF && n>=c++{ s = s OFS $0 }
  •   
     

如果设置了变量s,则记录至少包含1个字段和变量   n大于或等于变量c++++增量   运算符),然后连接变量s

     
      
  • c==n{print s; s=c=""}
  •   
     

如果变量c等于变量n,则打印变量s,然后   取消变量sc

<强>输入:

$ cat infile
*i 80.95.226.72/29 n/a None

  193.105.101.26                                     None        -
  28834 64690

*? 85.118.193.0/25 n/a None

  193.105.101.26                                     None        -
  28834 64814

u*>i 213.226.55.0/24 n/a None

  193.105.101.27                                     None        -
  28834 64757

<强>输出-1:

$ awk -v OFS=, 'NF{$1=$1; s=(s?s OFS:"") $0}NF==2 && s{print s; s=""}' infile
*i,80.95.226.72/29,n/a,None,193.105.101.26,None,-,28834,64690
*?,85.118.193.0/25,n/a,None,193.105.101.26,None,-,28834,64814
u*>i,213.226.55.0/24,n/a,None,193.105.101.27,None,-,28834,64757

<强>输出-2:

$ awk -v OFS=, -v n=2 'NF{$1=$1}/\*/{s=$0;next}s && NF && n>=c++{s = s OFS $0}c==n{print s; s=c=""}' infile
*i,80.95.226.72/29,n/a,None,193.105.101.26,None,-,28834,64690
*?,85.118.193.0/25,n/a,None,193.105.101.26,None,-,28834,64814
u*>i,213.226.55.0/24,n/a,None,193.105.101.27,None,-,28834,64757

答案 2 :(得分:0)

你能不能尝试跟随awk。

awk 'NF{gsub(/ +/,",");printf("%s",!/^,/?(NR!=1?RS $0:$0):$0)} END{print ""}'  Input_file

输出如下。

*i,80.95.226.72/29,n/a,None,193.105.101.26,None,-,28834,64690
*?,85.118.193.0/25,n/a,None,193.105.101.26,None,-,28834,64814
u*>i,213.226.55.0/24,n/a,None,193.105.101.27,None,-,28834,64757

现在也添加解释和非单线形式的解决方案。

awk '
NF{                                       ##If a line is NON-empty then do following steps.
  gsub(/ +/,",");                         ##Globally substituting all continuous spaces with a single comma in each non-empty line.
  printf("%s",!/^,/?(NR!=1?RS $0:$0):$0)  ##printing line here with a condition if line number is NOT equal to 1 and starts with comma then print RS(whose default value is a new line and current line) else print current line, outer else print current line.
}
END{
  print ""                                ##Printing NULL value here to print a new line.
}
' Input_file                              ##Mentioning Input_file name here too.