我有一个简单的问题。我需要删除两个模式之间所有出现的\n 。即。
<INFOSTART
A=1
B=2
C=3
D=4
<INFOEND
<INFOSTART
G=1
Z=3
<INFOEND
所以我希望输出如下所示
A=1 B=2 C=3 D=4
G=1 Z=3
知道我该怎么做吗?提前谢谢大家..
最佳答案
您可以使用带有 awk
的简单状态机, 例如下面的输入文件, 稍作修改以允许 outside 标记的文本(如果没有这样的文本,它仍然会按需要工作,这只是为了处理 extra 例):
xyzzy
plugh
<INFOSTART
A=1
B=2
C=3
D=4
<INFOEND
twisty
passages
<INFOSTART
G=1
Z=3
<INFOEND
after
last
使用这样的数据文件(或您的原始文件),以下 awk
命令为您提供所需的内容,将开始标记和结束标记之间的行组合成一行:
awk ' /^<INFOSTART$/ {inside=1; sep=""; next}
/^<INFOEND$/ {inside=0; print ""; next}
inside {printf sep""$0; sep=" "; next}
{print}' input_file
xyzzy
plugh
A=1 B=2 C=3 D=4
twisty
passages
G=1 Z=3
after
last
检查 awk
代码更详细,以下部分将在每一行展开。
只要您发现一行仅包含开始标记,就会运行以下片段。它设置了 inside
state 为 true(非零)以指示您应该开始组合行,并将初始分隔符设置为空字符串以确保组合行上没有前导空格。 next
简单地去并立即获取下一个输入行,开始一个新的循环:
/^<INFOSTART$/ {inside=1; sep=""; next}
假设您没有找到开始标记,则此段将运行结束标记。如果找到,inside
state 设置回 false(零)以开始打印出与输入文件中完全相同的行。它还输出一个换行符以正确完成组合行,然后使用下一个输入行重新启动循环:
/^<INFOEND$/ {inside=0; print ""; next}
如果您确定该行既不是开始标记也不是结束标记,您的行为取决于 inside
状态。对于 true,您需要将输入行组合成一个输出行,因此您只需打印,没有尾随换行符,分隔符后跟行本身。然后将分隔符设置为空格,以便下一行输入与前一行正确分隔。然后循环返回下一个输入行:
inside {printf sep""$0; sep=" "; next}
最后,如果你到达这里,你就知道你在开始/结束部分之外,所以你只需完全按照输入文件中存在的行来回显:
{print}'
如果您不想要格式良好的版本,您可以使用以下缩小版本,假设您确定唯一的 <INFO...
行是开始和结束标记:
awk '/^<INFOS/{a=1;b="";next}/^<INFOE/{a=0;print"";next}a{printf b$0;b=" ";next}1'
但是,由于这可能会在脚本中而不是单行命令中,因此我倾向于自己坚持使用可读版本。
关于bash - 删除两个模式(sed 或 awk?)之间出现的所有换行符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33120215/