这个shell / sed脚本有什么问题?

时间:2012-05-17 02:34:29

标签: regex bash sed

我在给定目录中有大约150个HTML文件,我想对其进行一些更改。一些锚标记沿着以下行具有href:index.php?page=something。我希望所有这些都改为something.html。简单的正则表达式,简单的脚本。不过,我似乎无法理解它。有人可以权衡我做错了吗?

示例html,输出前后:

<!-- Before -->
<ul>
    <li><a href="#">Apple</a></li>
    <li><a href="index.php?page=dandelion">Dandelion</a></li>
    <li><a href="index.php?page=elephant">Elephant</a></li>
    <li><a href="index.php?page=resonate">Resonate</a></li>
</ul>

<!-- After -->
<ul>
    <li><a href="#">Apple</a></li>
    <li><a href="dandelion.html">Dandelion</a></li>
    <li><a href="elephant.html">Elephant</a></li>
    <li><a href="resonate.html">Resonate</a></li>
</ul>

脚本文件:

#! /bin/bash

for f in *.html
do
    sed s/\"index\.php?page=\([.]*\)\"/\1\.html/g < $f >! $f
done

3 个答案:

答案 0 :(得分:4)

这是你的正则表达式,以及shell试图解释你的正则表达式的事实。

首先 - [.]*匹配任意数量的文字点.。将其更改为.*

其次,将整个正则表达式用单引号'括起来,以防止bash shell解释其中任何一个。

sed 's/"index\.php?page=\(.*\)"/\1\.html/g'

此外,代替< $f >! $f,您只需将'-i'开关输入sed即可使其就地运行:

sed -i 's/"index\.php?page=\(.*\)"/"\1\.html"/g' "$f"

(另外,我认为在你的替换中你需要在\1.html周围加上双引号,以便在HTML中引用新的网址。我还引用了你的$f到{{1} },因为如果文件名包含空格bash会抱怨)。

编辑:正如@TimPote所说,匹配引号内的内容的标准方法是"$f"(以便".*?"非贪婪)或{{1 }}。 Sed不支持前者,所以试试:

.*

这是为了防止(例如)"[^"]+"变成sed -i 's/"index\.php?page=\([^"]\+\)"/"\1\.html"/g' "$f" <a href="index.php?page=asdf">"asdf"</a>抓取<a href="asdf">"asdf.html"</a>,贪婪)。

答案 1 :(得分:1)

你的.*太贪心了。请改用[^"]\+。加上你的报价都搞砸了。改为使用单引号包围整个事物,然后您可以使用"而无需转义它们。

sed -i 's/"index\.php?page=\([^"]\+\)"/"\1\.html"/g'

您可以使用find

使用单个语句执行此整个操作
find . -maxdepth 1 -type f -name '*.html' \
 -exec sed -i 's/"index\.php?page=\([^"]\+\)"/"\1\.html"/g' {} \+

答案 2 :(得分:0)

以下作品:

 sed "s/\"index\.php?page=\(.*\)\"/\"\1.html\"/g" < 1.html 

我认为它主要是方括号。不知道为什么你有它们。 哦,整个sed命令需要在引号中。