bash - 删除两个模式(sed 或 awk?)之间出现的所有换行符

标签 bash awk sed

我有一个简单的问题。我需要删除两个模式之间所有出现的\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/

相关文章:

linux - 通过 ssh 运行程序失败并显示 "Error opening terminal: unknown."

linux - bash 中类似 pgrep 的高级进程搜索

bash - 在 awk 中使用记录分隔符

awk - 为什么 (g)awk 反转这些输出行?

linux - 如何使用 cat、sed、awk 或 cut 将列添加到 csv 文件中的特定位置?

linux - 我如何比较 3 个文件(以查看它们之间的共同点)?

arrays - 如何查找并提取出现在括号之间的所有单词?

linux - 尝试了解 PATH 在 Linux 上的设置方式(Ubuntu 16.04 上的 bash)

unix - sed - 如何覆盖可选空间?

linux - 如何使用 sed 's/$var/$var2' 文件