![使用 ed(1) 在 HTML 标签内进行编辑](https://linux22.com/image/228884/%E4%BD%BF%E7%94%A8%20ed(1)%20%E5%9C%A8%20HTML%20%E6%A0%87%E7%AD%BE%E5%86%85%E8%BF%9B%E8%A1%8C%E7%BC%96%E8%BE%91.png)
考虑一下我的卑微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