Input:
1:
aaa
bbb
2:
xxx
yyy,
zzz
3:
ccc
4:
5:
xxx
yyy
输出:
1: aaa bbb
2: xxx yyy, zzz
3: ccc
4:
5: xxx yyy
:$
要求:合并模式 1和模式 2之间的所有行:$
(包括模式 1 但不包括模式 2)
正则表达式匹配::$
尝试过:
sed '/:$/{n;:l N;/:$/b; s/\n/ /; bl}' | sed '/:$/!b;/:$/N;/:$/!{s/\n//g}' -E
答案1
使用 Perl:
$ perl -0 -pe 's/\n+/ /g;
s/ (\d+:)/\n$1/g;
s/^\n+//;
s/ +$/\n/' input.txt
1: aaa bbb
2: xxx yyy, zzz
3: ccc
4:
5: xxx yyy
(为了便于阅读,在脚本中添加了换行符。它按原样运行,或者您可以删除它们以获得难以理解的单行代码)
- 首先,它用一个空格替换一个或多个换行符的所有实例(注意:这具有删除/忽略空行的额外有用的副作用)。
- 然后它替换所有实例中的空格一个空格、一个或多个数字和一个
:
带换行符。 - 然后它删除字符串开头的所有前导换行符,并用单个换行符替换字符串末尾的所有尾随空格。这是必需的,因为之前的 s/// 替换操作将所有换行符替换为空格。
该-0
选项告诉 perl 使用 NUL 作为输入记录分隔符,并且由于输入不包含任何 NUL,这使得它将整个输入文件作为一个长字符串处理。
perl 的-p
选项使其工作方式类似于sed
用“读取、处理和自动打印”循环包装整个单行脚本。顺便说一句,-n
perl 相当于 sed 的-n
选项(“读取、处理但不自动打印”循环)。
man perlrun
有关这些 、 和 选项的详细信息-0
,-p
请参阅-n
。
答案2
和awk
:
$ awk -v ORS= '/:$/{print n; n="\n"; s=""} {print s $0; s=" "} END{print n}' ip.txt
1: aaa bbb
2: xxx yyy, zzz
3: ccc
4:
5: xxx yyy
-v ORS=
输出记录分隔符的空值/:$/{print n; n="\n"; s=""}
- 第一次
n
将为空(以避免在第一行之前打印换行符) s
每次找到匹配项时都会被清空
- 第一次
{print s $0; s=" "}
- 打印
s
后跟输入行 s
仅对于不以以下结尾的行来说是空格字符:
- 打印
答案3
您可以使用“可调整大小”的滑动窗口 -$!N
通常与 一起使用,P
并且D
只有在这里您需要在条件下执行此操作:将行累积到模式空间中,只要模式空间不匹配,就用空格替换换行符,/:$/
否则打印并删除到换行符并重复:
sed '/:$/{
:do
$!N;/:$/{
P;D
}
s/\
/ /
t do
}' infile
如果您更喜欢gnu sed
单行语法:
sed '/:$/{:do;$!N;/:$/{P;D;};s/\n/ /;t do}' infile
答案4
使用 tr 和 sed 可能更容易:
$ tr '\n' ' ' <infile | sed 's/ [0-9]/\n&/g' | sed 's/^ //'
1: aaa bbb
2: xxx yyy zzz
3: ccc
4:
5: xxx yyy
(如果对齐不是问题,您甚至可以省略上面代码中的第二个 sed)