将文件中的多行合并为一行

将文件中的多行合并为一行

我有如下文件..

"Field1"|"Field2"|"Field3"|"ufghjkrtyrtyfgh$"  
"Field1"|"Field2  
continue on line 2  
continue on line 3"|"Field3"|"ufghjkrtyrtyfgh$"  
"Field1"|"Field2"|"Field3"|"ufghjkrtyrtyfgh$"

我正在寻找如下的输出

"Field1"|"Field2"|"Field3"|"ufghjkrtyrtyfgh$"  
"Field1"|"Field2continue on line 2continue on line "|"Field3"|"ufghjkrtyrtyfgh$"  
"Field1"|"Field2"|"Field3"|"ufghjkrtyrtyfgh$"  
  1. 每条记录将以$"
  2. 字段 2 可以分布在多行中
  3. 文件以竖线分隔并用双引号括起来。

你能帮我解决这个问题吗?

答案1

$ awk '/[$]"[[:space:]]*$/{print;next} {printf "%s",$0}' file
"Field1"|"Field2"|"Field3"|"ufghjkrtyrtyfgh$"
"Field1"|"Field2continue on line 2continue on line 3"|"Field3"|"ufghjkrtyrtyfgh$"
"Field1"|"Field2"|"Field3"|"ufghjkrtyrtyfgh$"

怎么运行的

  • /[$]"[[:space:]]*$/{print;next}

    对于以 结尾的任何行$"后面可以跟空格,这将 (1) 打印该行,并且 (2) 跳过剩余命令并告诉 awk 从该next行重新开始。

    在 awk 正则表达式中,$表示行尾。如果我们想匹配一个实际的美元符号,我们必须以某种方式对其进行转义。对其进行转义的最可靠方法是将其放在方括号中:[$]。在上面的正则表达式中,[$]后面跟着双引号",后面跟着[[:space:]]*。字符类[[:space:]]匹配任何空格字符,意味着*我们应该匹配零个或多个。后面跟着未转义的字符$,它匹配行尾。

  • printf "%s",$0

    对于任何其他行,这将告诉 awk 打印该行没有换行符。

答案2

echo '"Field1a"|"Field2a"|"Field3a"|"ufghjkrtyrtyfgh$"
"Field1b"|"Field2b
continue on line 2                              
continue on line 3"|"Field3b"|"ufghjkrtyrtyfgh$"
"Field1c"|"Field2c"|"Field3c"|"ufghjkrtyrtyfgh$"' | sed -nr '/^".*"$/{p;n};:a;/[^"]$|^[^"]/{N;s/(.)\n(.)/\1\2/;ta};p'
"Field1a"|"Field2a"|"Field3a"|"ufghjkrtyrtyfgh$"
"Field1b"|"Field2bcontinue on line 2continue on line 3"|"Field3b"|"ufghjkrtyrtyfgh$"
"Field1c"|"Field2c"|"Field3c"|"ufghjkrtyrtyfgh$"

sed 解决方案。以“”开头和结尾的每一行都将被打印,然后 'n' 命令读取下一行并开始新的循环。如果一行不是以“”开头或结尾,它将进入循环 ':a .... ta',然后 'N' 命令附加下一行,'s' 命令将“lastchar”“newline”“firstchar”替换为“lastchar”“firstchar”('(.)\n(.)' 部分),然后只有当 's' 命令实际替换某些内容时(这是循环),'ta' 命令才会跳转到“:a”标记。如果 's' 没有替换任何内容,'ta' 不会跳转到标记,sed 会“打印”结果行并从下一行开始新的循环。awk 解决方案确实看起来干净得多。我认为我的 sed 解决方案可以改进。

编辑:-n 选项抑制自动 sed 输出,因此我们只用“p”打印我们想要的内容。-r 选项用于高级正则表达式。

答案3

稍微不同的 GNUawk解决方案:

awk -v RS='\\$" *' '{gsub(" *\n", ""); print $0 RT }' file

这使用正则表达式作为记录分隔符。

相关内容