使用awk将行合并为一行

时间:2018-09-06 12:32:51

标签: awk

我有一个包含以下记录的文件

ABC
BCD
CDE
EFG

我想将其转换为

'ABC','BCD','CDE','EFG'

我尝试通过以下方式使用Awk来解决此问题:

awk '/START/{if (x)print x;x="";next}{x=(!x)?$0:x","$0;}END{print x;}'

但是我没有得到我所期望的:

ABC,BCD,CDE,EFG

关于如何实现这一目标,是否有任何建议?

4 个答案:

答案 0 :(得分:2)

请您尝试以下。

awk -v s1="'" 'BEGIN{OFS=","} {val=val?val OFS s1 $0 s1:s1 $0 s1} END{print val}' Input_file

输出如下。

'ABC','BCD','CDE','EFG'

答案 1 :(得分:2)

使用GNU awk进行多字符RS:

$ awk -v RS='\n$' -F'\n' -v OFS="','" -v q="'" '{$1=$1; print q $0 q}' file
'ABC','BCD','CDE','EFG'

答案 2 :(得分:1)

有很多方法可以实现这一目标:

带管道:

sed "s/.*/'&'/" <file> | paste -sd,
awk '{print '"'"'$0'"'"'}' <file> | paste -sd,

备注:在这里我们不使用tr,因为这样会在末尾产生额外的,

将完整文件读入内存:

sed ':a;N;$!ba;s/\n/'"','"'/g;s/.*/'"'&'"'/g' <file>  #POSIX
sed -z 's/^\|\n$/'"'"'/g;s/\n/'"','"'/g;' <file>      #GNU

@EdMorton

的解决方案

不将完整文件读入内存:

awk '{printf (NR>1?",":"")"\047"$0"\047"}' <file>

和一些其他随机尝试:

awk '(NR-1){s=s","}{s=s"\047"$0"\047"}END{print s}' <file>
awk 'BEGIN{printf s="\047";ORS=s","s}(NR>1){print t}{t=$0}END{ORS=s;print t} <file>

那么OP的尝试是怎么回事?

写下OP的awk行,

/START/{if (x)print x;x="";next}
{x=(!x)?$0:x","$0;}
END{print x;}

这是做什么的?让我们逐步分析:

  • /START/{if (x)print x;x="";next} :: 读取为如果当前记录/行包含字符串START,则执行

    • if (x) print x ::如果x不是空字符串,则输出x的值
    • x=""x设置为空字符串
    • next ::跳至下一条记录/行

    在此代码块中,OP可能假设/START/意味着在所有事物的开始处执行此操作。但是在awk中,它写为BEGIN,并且由于开头所有变量都是空字符串或零,因此默认情况下不执行if语句。此块可以替换为:

    BEGIN{x=""}
    

    但是再次,这不是必需的,因此可以将其删除:

  • {x=(!x)?$0:x","$0;} :: 将字符串与正确的定界符连接起来。这很好,尤其是由于使用了三元运算符。可悲的是,分隔符设置为,而不是',',而awk中最好将其写为\047,\047。因此该行可能显示为:

    {x=(!x)?$0:x"\047,\047"$0;}
    

    如果您意识到x可能是一个空字符串,则可以将这一行写得更短。对于空字符串,x=$0等效于x=x $0,您要做的就是添加一个分隔符,该分隔符可以全部为空,也可以不为空字符串。因此,您可以将其写为

    {x= x ((!x)?"":"\047,\047") $0}
    

    或反转逻辑以摆脱一些其他字符:

    {x=x(x?"\047,\047":"")$0}
    

    一个人甚至可以写

    {x=x(x?"\047,\047":x)$0}
    

    但这不是最佳选择,因为它需要再次读取x的内存。但是,可以使用这种形式将其最终优化为(每个@EdMorton's comment

    {x=(x?x"\047,\047":"")$0}
    

    这更好,因为它删除了一个额外的串联运算符。

  • END{print x} :: 在这里,OP打印结果。但是,这将丢失字符串开头和结尾的最后的单引号,因此可以添加它们。

    END{print "\047" x "\047"}
    

因此,OP代码的更正版本为:

awk '{x=(x?x"\047,\047":"")$0}END{print "\047" x "\047"}'

答案 3 :(得分:0)

awk可能更好

awk '{printf fmt,$1}' fmt="'%s'\n" file | paste -sd, -

'ABC','BCD','CDE','EFG'