sed - 在模式中包含换行符

时间:2013-07-16 08:16:39

标签: regex shell sed cygwin

我仍然是shell脚本的菜鸟,但我正在努力。下面是一个部分工作的shell脚本,它应该通过匹配标记并删除其附带的内容来从* .htm文档中删除所有JS。例如。 <script src=""><script></script><script type="text/javascript">

find $1 -name "*.htm" > ./patterns
for p in $(cat ./patterns)
do
sed -e "s/<script.*[.>]//g" $p #> tmp.htm ; mv tmp.htm $p
done

这个问题是脚本是因为sed逐行读取文本输入,所以这个脚本不能按预期用新行工作。运行:

<script>
//Foo
</script>

将删除第一个脚本标记,但会省略我不想要的“foo”和结束标记。

有没有办法匹配正则表达式中的换行符?或者,如果sed不合适,我还可以使用其他任何东西吗?

3 个答案:

答案 0 :(得分:5)

假设您在不同的行上有<script>个标记,例如类似的东西:

foo
bar
<script type="text/javascript">
some JS
</script>
foo

以下内容应该有效:

sed '/<script/,/<\/script>/d' inputfile

答案 1 :(得分:1)

awk脚本将查找<script*>标记,设置in变量,然后阅读下一行。找到结束</script*>标记时,变量设置为零。如果in变量为零,则最终打印模式输出所有行。

awk '/<script.*>/   { in=1; next }
     /<\/script.*>/ { if (in) in=0; next }
    { if (!in) print; } ' $1

答案 2 :(得分:0)

正如您所提到的,问题是sed逐行处理输入。

因此,最简单的解决方法是将输入设为单行,例如用输入中不存在您确信的字符替换换行符。

人们很想使用tr

… |tr '\n' '_'|sed 's~<script>.*</script>~~g'|tr '_' '\n'

然而“currently tr fully supports only single-byte characters”,为了安全起见,您可能想要使用ˇ之类的不可能的字符,而tr对此无效。

幸运的是,使用sedusing branching可以实现同样的目标。

回到我们的<script>…</script>示例,这确实有效,并且(根据之前的链接)跨平台:

… |sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ˇ/g' -e 's~<script>.*</script>~~g' -e 's/ˇ/\n/g'

如果您使用GNU sed并且不需要跨平台兼容性,则采用更精简的形式:

… |sed ':a;N;$!ba;s/\n/ˇ/g;s~<script>.*</script>~~g;s/ˇ/\n/g'

有关分支部分(:a;N;$!ba;)的详细信息,请参阅“使用分支”下的链接答案。剩下的部分很简单:

  • s/\n/ˇ/gˇ;
  • 替换所有换行符
  • s~<script>.*</script>~~g删除了需要删除的内容(请注意,实际使用时需要一些安全保护:因为它会删除第一个<script>和最后一个</script>之间的所有内容;此外,请注意,我使用了~而不是/来避免在</script>中转义斜杠:我可以使用几乎任何单字节字符,除了一些保留的字符,例如{{1} });
  • \读取换行符。