使用sed在多行中进行懒惰查找和替换

4
我正在尝试使用sed从文件中删除html代码块。要删除的块在文件中出现多次,且跨越多行。注意,该块内容不同,但有清晰的起始和结束标记。
我已经尝试了许多方法来实现这个目标,但在sed中实现惰性匹配和跨行匹配时遇到了问题。
以下是我要做的事情的示例:
good stuff a
good stuff same line START
bad stuff 1.0
bad stuff 1.1
END
good stuff b
good stuff b
good stuff same line START bad stuff 2.0
bad stuff 2.0
END
good stuff c

Becomes:

good stuff a
good stuff same line
good stuff b
good stuff b
good stuff same line
good stuff c

以下是我迄今为止尝试过的几种方法。

sed -n '1h;1!H;${;g;s/START.*END//mg;p;}' < test > test2 通过跨越多行进行处理。

sed -n 's/START[^END]*END//g' < test > test2 只否定了E或N或D。

sed -n 's/START.*?END//g' < test > test2 懒惰模式未能实现。

谢谢。

5个回答

2

sed不适合处理多行输入。使用awk代替。
您想匹配一行的正则表达式,并在它是“坏”块的开头时关闭打印。以下是文件的示例:

$ awk '
BEGIN    { pr = 1; }
/^START/  { pr = 0; }
          { if (pr) print; }
/^END/    { pr = 1; }
' < yourfile
good stuff a
good stuff b
good stuff b
good stuff c

这会占用整行的空间,因此不符合问题的要求。 - Josh

1
这可能适用于您(GNU sed):
sed '/START/!b;:a;/END/bb;$!{N;ba};:b;s/START.*END//' file

能够很好地处理START和END在一行中的位置以及多次出现的情况。 - Josh

1
怎么样:
$ sed '/START/,/END/d' file.txt
good stuff a
good stuff b
good stuff b
good stuff c

阅读更多关于ranges的内容在这里


1
一个 sed 可能很难做到这一点。两个 sed 就变得非常简单:
sed 's/START/\nSTART\n/g' | sed '/START/,/END/d'

这似乎没有在我的终端中添加换行符。 - Alex Unger
它对我来说完全按照你在问题中请求的方式工作。目标不是添加换行符,而是将START移动到单独的一行,然后通过范围删除将其删除。 - aragaer
让sed理解换行符的一种可移植方法是将其硬编码为反斜杠后跟回车符。 - Ed Morton

0

sed是在单行上进行简单替换的绝佳工具,对于其他任何事情,请使用awk:

$ awk 'sub(/START.*|.*END/,""){f=!f;if(NF)print;next} !f' file
good stuff a
good stuff same line
good stuff b
good stuff b
good stuff same line
good stuff c

解决了这个特定的问题,但没有使用sed,并且对某些边缘情况不起作用(请参见potong的解决方案)。 - Josh
显然,它不使用sed,因为这不是sed适合的工作。你指的是哪些边缘情况? - Ed Morton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接