使用 ed(1) 在 HTML 标签内进行编辑

使用 ed(1) 在 HTML 标签内进行编辑

考虑一下我的卑微hello.html文件,用强大的编辑编辑:

$ ed hello.html 
28
,p
<title>Hello world!</title>

您在其中进行编辑的一般方法是什么标题HTML 标签(如果您可以在任何 HTML 标签内进行编辑,那就更好了)?

我尝试了在标签内匹配的正则表达式:

s/>.*/>My new title/p
<title>My new title
u
.
<title>Hello world!</title>

但是,可悲的是,你可以看到我砍掉了我的标签(而且打印出来的工作量太大了)</title>每次都咬一下!)。

为了进一步学习,我浏览了 Pascal 中的 Software Tools 页至 174 — 请参阅https://archive.org/details/softwaretoolsinp00kern/page/174/mode/1up?view=theater页面——并发现了&有助于达到的特殊字符中间句子的:

s/world/& again/p
<title>Hello world again!</title>

但是,这不太正确,因为我想替换中间,而不仅仅是到达中间。

答案1

您可以使用[^<]代替来.匹配除<代替之外的任何字符。

28
ed> ,n
1       <title>Hello world!</title>
ed> s/>[^<]*/>new title/
ed> ,n
1       <title>new title</title>

<另一种方法可能是在每个或之后插入换行符,以便>您想要更改的内容在其自己的行上,您可以c使用以下命令进行更改c

28
ed> ,n
1       <title>Hello world!</title>
ed> s/[<>]/\
&\
/g
ed> ,n
1
2       <
3       title
4       >
5       Hello world!
6       <
7       /title
8       >
9
ed> 5c
new title
.
ed> ,n
1
2       <
3       title
4       >
5       new title
6       <
7       /title
8       >
9
ed> 1,9j
ed> ,n
1       <title>new title</title>

答案2

更好的方法是使用 HTML 感知解析器并使用它来编辑内容。我更喜欢的工具是xmlstarlet因为虽然它是一个 XML 解析器/编辑器,但它也可以处理 HTML:

创建示例页面

cat >my.html <<'EOF'
<html>
<title>Hello world!</title>
<body><p>Thank you for reading my page</p></body>
</html>
EOF

Hello world!用。。。来代替Hello everyone!

xmlstarlet format --html my.html 2>/dev/null |
    xmlstarlet edit --omit-decl --update '//title' --value 'Hello everyone!'

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
  <head>
    <title>Hello everyone!</title>
  </head>
  <body>
    <p>Thank you for reading my page</p>
  </body>
</html>

输出被写入标准输出,而这里通常的做法是将其写入临时文件,然后替换原来的。这并不完美,但可能是可以接受的:

file=my.html
(
    [ "${file#/}" = "$file" ] && file="./$file"

    xmlstarlet format --html "$file" 2>/dev/null |
        xmlstarlet edit --omit-decl --update '//title' --value 'Hello everyone!' >"$file.tmp" &&
        cp -p -- "$file" "$file.old" &&
        mv -f -- "$file.tmp" "$file"
)

请注意,如果$file以以下方式开头,-您将收到错误xmlstarlet,并且您无法使用--它将其与真实选项分开。我们在这里所做的是检查文件名是否是绝对的,如果不是,则在前面添加./.cp如果不需要保存原始内容的副本,可以省略该行。

答案3

您不应该使用正则表达式来解析 HTML。看https://stackoverflow.com/questions/1732348/regex-match-open-tags- except-xhtml-self-contained-tags

如果您想使用ed下面的代码来执行此操作,请为您提供的 HTML 标记执行此操作。但使用可能会更好sed。这是有效的,因为您可以将任何字符与 一起使用s,不必是s/old/new/它可以是s|old|new|or s!old!new!

$ ed hello.html
28
,p
<title>Hello world!</title>
s|<title>.*</title>|<title>foo</title>|
,p
<title>foo</title>

/ 字符可以统一替换为任何给定 s 命令中的任何其他单个字符。仅当 / 字符(或替代它的任何其他字符)前面有 \ 字符时,它才可以出现在正则表达式或替换中。

https://www.gnu.org/software/sed/manual/html_node/The-_0022s_0022-Command.html

相关内容