简单的多行sed命令不太有用

时间:2014-09-29 17:16:46

标签: sed multiline

我希望匹配包含换行符在内的一些文字。下面的命令几乎可以工作,但它与第一​​行不匹配

(echo foo; echo foo; echo bar) | sed '1!N; s/foo.*bar/zap\nbaz/'
foo
zap
baz

这里有同样的问题:

(echo foo; echo bar; echo bar) | sed '1!N; s/foo.*bar/zap\nbaz/'
foo
bar
bar

我发现了一个更复杂的sed命令,它在两种情况下都能正常工作,但我宁愿修复简单的命令(如果可能的话),或者至少理解为什么它不起作用。

(echo foo; echo bar; echo bar) | sed -n '1h;1!H;${g;s/foo.*bar/zap\nbaz/p}'
zap
baz

4 个答案:

答案 0 :(得分:3)

对于任何涉及多行的事物而言,sed非常简单,因为它是面向行的,因此设计为一次处理一行。用于处理多行输入的所有sed的语言结构在20世纪70年代中期被发明时已经过时了,因为awk是面向记录而不是面向行的,因此就像任何其他角色一样简单地处理记录中的换行符。例如:

$ (echo foo; echo bar; echo bar) |
    awk -v RS= '{sub(/foo.*bar/,"zap\nbaz"); print}'
zap
baz

任何时候你发现自己在sed中使用的不仅仅是s,g和p(和-n),或者在谈论“空格”时,你的方法是错误的。

答案 1 :(得分:0)

您的简单方法一次最多可以在模式空间中保存两行文本,因此无法匹配三行模式。

特别是:

(echo foo; echo foo; echo bar) | sed '1!N; s/foo.*bar/zap\nbaz/'
foo
zap
baz

它读取第一行(foo),找不到匹配项,并打印foo。然后它读取第二个(foo),追加下一个(bar),找到匹配并执行替换,然后打印zap\nbaz

在第二轮中:

(echo foo; echo bar; echo bar) | sed '1!N; s/foo.*bar/zap\nbaz/'
foo
bar
bar

它读取第一行(foo),找不到匹配项,并打印foo。然后它读取第二个(bar),追加下一个(bar),找不到匹配并打印bar\nbar

答案 2 :(得分:0)

这是一个解决方法

sed 's/$/\\n/' | tr -d '\n' | sed 's/foo.*bar/zap\\nbar/g' | sed 's/\\n/\n/g'

答案 3 :(得分:0)

这可能适合你(GNU sed):

sed '/foo/{:a;N;/foo.*bar/!ba;s//zap\nbaz/}' file

如果当前行包含foo,则附加换行符和下一行,然后查找foo后跟bar(包括换行符在内的任意数量的字符)。如果找到此模式,请将其替换为zap\nbaz并打印出结果。如果没有循环回:a并重复直到找到它或文件结束(在这种情况下,模式空间中的整个字符串将被打印出来而没有任何变化)。

N.B。 N命令不允许您读取传递文件结尾并尝试拯救它。命令s//zap\nbaz/将当前正则表达式替换为zap\nbaz,其中当前正则表达式是此/.../中的最后一个/foo.*baz/

没有大括号的替代方案:

sed '/foo/!b;:a;N;/foo.*bar/!ba;s//zap\nbaz/' file