如何将多行合并为单行,但仅适用于由空行分隔的行块
Posted
技术标签:
【中文标题】如何将多行合并为单行,但仅适用于由空行分隔的行块【英文标题】:How to merge multiple lines into single line but only for block of lines separated by blank line 【发布时间】:2019-08-22 02:29:01 【问题描述】:我正在尝试将多行合并为单行,但有附加条件。
我的输入文件如下所示:
Dm1*( stuff1 + stuff2 -
stuff3 + stuff4)
+ D1*(D1stuff1 + D1sstuff2 + D1stuff3 + D1stuff4 +
D1stuff5 -
D1stuff6 )
+ D2*(D2stuff)
所以有多行也用空行分隔。所有的*stuff*
都包含长而复杂的表达式,也可以包含括号。
我想保留空白行,但合并其他多行。
预期的输出是
Dm1*( stuff1 + stuff2 - stuff3 + stuff4)
+ D1*(D1stuff1 + D1sstuff2 + D1stuff3 + D1stuff4 + D1stuff5 - D1stuff6 )
+ D2*(D2stuff)
当前的所有尝试都喜欢
awk 'printf("%s",$0)'
将所有内容放在一行中。我应该遍历行还是有什么方法可以识别空行之间的块并将其应用到其中?
【问题讨论】:
【参考方案1】:甚至比 John1024 的版本短了一点
awk 'BEGIN RS=""; ORS="\n\n"$1=$11'
或
awk -v RS="" -v ORS="\n\n" '$1=$11'
使用RS=""
告诉 awk 使用任何段落作为记录(即由空行分隔的文本块)。但它也告诉 awk FS
组合的字段分隔符。只需重新定义输出记录分隔符ORS
,我们就可以通过重置第一条记录$1=$1
告诉awk 重新定义其记录$0
来输出您想要的所有内容。这意味着由FS
(这里的默认值)和换行符(由于RS=""
)定义的所有字段分隔符都被OFS
(默认为1
打印记录
另外设置OFS=""
可以去掉所有空格
RS
RS
的字符串值的第一个字符为输入记录分隔符;默认情况下。如果 RS
包含多个字符,则未指定结果。如果RS
是null
,则记录由加上一个或多个空行组成的序列分隔,前导或尾随空行不应导致输入的开头或结尾处为空记录,并且 应始终是字段分隔符,无论 FS
的值是什么。来源:POSIX awk standard
【讨论】:
之前的第二个中缺少'
?
是的,这是使用 awk 执行此操作的正确/惯用方式。【参考方案2】:
awk 'if(NF!=0)printf $0elseprintf "\n\n"'
【讨论】:
【参考方案3】:试试:
$ awk -v RS= 'gsub(/ *\n */, " "); print $0 ORS' file
Dm1*( stuff1 + stuff2 - stuff3 + stuff4)
+ D1*(D1stuff1 + D1sstuff2 + D1stuff3 + D1stuff4 + D1stuff5 - D1stuff6 )
+ D2*(D2stuff)
它是如何工作的:
-v RS=
这告诉 awk 使用空行作为记录分隔符。
gsub(/ *\n */, " ")
这告诉 awk 用一个空格替换记录中的任何换行符以及周围的任何空格。
print $0 ORS
这告诉 awk 打印记录,后跟输出记录分隔符 ORS
,默认情况下是换行符。
【讨论】:
【参考方案4】:除了John1024 引入的非常好的awk
命令之外,您还可以使用sed
方法来解决您的问题。
输入:
$ cat input_file
Dm1*( stuff1 + stuff2 -
stuff3 + stuff4)
+ D1*(D1stuff1 + D1sstuff2 + D1stuff3 + D1stuff4 +
D1stuff5 -
D1stuff6 )
+ D2*(D2stuff)
命令:
sed -n '/^$/!H;/^$/x;s/\n//g;s/$/\n/;p;;$x;s/\n//g;p' input_file
输出:
Dm1*( stuff1 + stuff2 -stuff3 + stuff4)
+ D1*(D1stuff1 + D1sstuff2 + D1stuff3 + D1stuff4 + D1stuff5 - D1stuff6 )
+ D2*(D2stuff)
说明:
-n
停用 sed
自动打印
/^$/!H;
当sed
遇到非空行时/^$/!
通过H
将此行附加到保留空间中
/^$/x;s/\n//g;s/$/\n/;p;
sed
遇到空行/^$/
,交换保持空间和模式空间x
,去掉已经构造好的s/\n//g
字符串中的所有\n
,在后面加一个\n
字符串结尾s/$/\n/
,打印它p
。
$x;s/\n//g;p
当sed
到达最后一行时,交换保持/模式空格x
,然后在打印之前通过s/\n//g
删除所有\n
p
。
【讨论】:
【参考方案5】:使用 Perl 段落模式
perl -00 -ne ' s/\n//g; print "$_\n\n" ' file
您的意见
$ cat bogey.txt
Dm1*( stuff1 + stuff2 -
stuff3 + stuff4)
+ D1*(D1stuff1 + D1sstuff2 + D1stuff3 + D1stuff4 +
D1stuff5 -
D1stuff6 )
+ D2*(D2stuff)
$ perl -00 -ne ' s/\n//g; print "$_\n\n" ' bogey.txt
Dm1*( stuff1 + stuff2 -stuff3 + stuff4)
+ D1*(D1stuff1 + D1sstuff2 + D1stuff3 + D1stuff4 + D1stuff5 - D1stuff6 )
+ D2*(D2stuff)
$
【讨论】:
【参考方案6】:这可能对你有用(GNU sed):
sed ':a;N;/\n$/!s/\n//;ta' file
在模式空间中收集行,删除换行符,直到空行。
【讨论】:
这适用于 GNU sed。但是我更喜欢在 GNU 和 BSD 平台上都可以使用的东西,因为我经常同时使用这两种平台。 @Boogeyman 也许sed $':a;N;/\\n$/!s/\\n//;ta' file
会起作用,或者也许sed -e ':a' -e $'N;/\\n$/!\\n//;ta' file
以上是关于如何将多行合并为单行,但仅适用于由空行分隔的行块的主要内容,如果未能解决你的问题,请参考以下文章