求批量替换的办法

2019-04-07 09:30:53 +08:00
 dazkarieh

我想检索当前目录下所有*.MD 文件的内容,如果遇到

![text](url)

就替换为

{{< img src="url" alt="text">}}

//这里的 text 是指方括号里的任意文本,url 是指括弧里的任意链接地址,并非特指。

试了一个大佬提供的办法

sed -i -r 's/\!\[(.*)\]\((.*)\)/{{<img src="\1" alt="\2">}}/' *.md

但是我这边报错

sed: 1: "s/\!\[(.*)\]\((.*)\)/{{ ...": \2 not defined in the RE

环境是 MacOS 系统,这要咋改?

3498 次点击
所在节点    Linux
15 条回复
geelaw
2019-04-07 09:42:03 +08:00
你的行动并没有代表本来的意思,因为并不是所有的 ![]() 都是图,而且有些图是有 alt 的。最简单的正确做法是用 Markdown 编译器把 Markdown 编译成 Markdown。

当然,实际情况是你的所有 ![]() 都是图,那么这样的替换也是不安全的,因为你忘记了非贪婪匹配。

第一种解决方法是在 macOS 上安装 GNU sed,然后用 GNU sed。

第二种解决方法是在 macOS 上输入 man sed,查看 macOS 的 sed 如何在替换字符串里用捕获组。
aaaaasam
2019-04-07 09:51:19 +08:00
s#\!\[\(.*\)\](\(.*\))#{{< img src="\1" alt="\2">}}
Belmode
2019-04-07 09:54:37 +08:00
这个正则太简单了,sed 命令 linux 支持,不知道 mac 是啥
dazkarieh
2019-04-07 10:19:34 +08:00
@aaaaasam -sh: syntax error near unexpected token `\(.*\)'
@geelaw 谢谢您的详细耐心解答,虽然没安装成 GNU SED,但至少明白问题出在哪儿了
@Belmode 兄嘚说的是,是我没搞明白
xy2401
2019-04-07 10:24:15 +08:00
我运行是成功都 是不是 -i 错了?
$ echo '#![text](url)' | sed -r 's/\!\[(.*)\]\((.*)\)/{{<img src="\1" alt="\2">}}/'
#{{<img src="text" alt="url">}}
dazkarieh
2019-04-07 10:26:10 +08:00
@xy2401 我装了 gsed,然后用下面测试成功了。

gsed -i -r 's/\!\[(.*)\]\((.*)\)/{{<img src="\2" alt="\1">}}/' *.md
xy2401
2019-04-07 10:29:35 +08:00
我试了一下 你的命令没问题 我是在 windows 上的 wsl 上尝试的 修改文件成功了

我一开始 echo 然后 -i 结果报错和你一样
echo '#![text](url)' | sed -i 's/\!\[(.*)\]\((.*)\)/{{<img src="\1" alt="\2">}}/'
sed: -e expression #1, char 49: invalid reference \2 on `s' command's RHS
aaaaasam
2019-04-07 11:39:35 +08:00
@dazkarieh s#\!\[\(.*\)\](\(.*\))#{{< img src="\1" alt="\2">}}# 少复制了一个#
TonyLiu2ca
2019-04-07 11:43:06 +08:00
@dazkarieh

看看这个过程
```
$ cat Test.MD
![text](url)
![Pci1]( http://aa.bb.cc)
![DATA1]( http://aa.bb.cc)
![Pci2]( http://bbb.com)
![]
![DATA_2]( http://bbb.com)
![( http://)
![]
( http://)
![] (
http://)

$ sed -E 's/\!\[(.*)\]\((.*:\/\/.*)(.*)\)/{{img src="\1" alt="\2\3"}}/' Test.MD
![text](url)
{{img src="Pci1" alt="http://aa.bb.cc"}}
{{img src="DATA1" alt="https://aa.bb.cc"}}
{{img src="Pci2" alt="http://bbb.com"}}
![]
{{img src="DATA_2" alt="https://bbb.com"}}
![( http://)
![]
( http://)
![] (
http://)
```

这个例子里面稍微做了一点对 url 的检测,假设符合“*://*”的格式,也就是 http://*, https://* 或 ftp://*等等,这个可能是多余,或者说并不完备,只是个例子。
aaaaasam
2019-04-07 11:43:16 +08:00
@dazkarieh sed -i -r 's#\!\[\(.*\)\](\(.*\))#{{< img src="\1" alt="\2">}}#' test.md
winglight2016
2019-04-07 16:27:52 +08:00
牛!没想到正则还能这么玩。。。我 google 了一下:convert md to html,工具挺多的,应该能满足 lz 需求
troyl
2019-04-07 16:59:52 +08:00
在 Mac 下使用 sed 的 in-place replacement 要在 -i 后面加 一个额外的 '' 。这个跟 Linux 是不一样的。
xy2401
2019-04-09 23:59:20 +08:00
问一下 lz 一个简单的问题 我今天有一个类似的需求。 有没有人帮忙解答一下
![text](url) --> ![text](../abcd/url) url 加一个前缀就可以了。需求很简单
http://url.html 不要匹配。url.html 匹配。 我只要要判断 \w 文本加一个 . 即可。可是 这个. 我总是无法匹配


$ echo '#![text](url.)' | sed -r 's/\]\((\w)/\]\(\.\.\/abcd\/\1/'
#![text](../abcd/url.)
$ echo '#![text](url.)' | sed -r 's/\]\((\w)\./\]\(\.\.\/abcd\/\1/'
#![text](url.)
xy2401
2019-04-10 08:47:21 +08:00
我 sb 了

\w 匹配包括下划线的任何单词字符。等价于“[A-Za-z0-9_]”。

我一直记成了 \w 是匹配完整的一个单词


# echo '#![text](url.html) #![text]( http://url.com) #![text](context/url.html)' | sed -r 's/\]\((\w*)([\.\/])/\]\(\.\.\/abcd\/\1\2/g'
#![text](../abcd/url.html) #![text]( http://url.com) #![text](../abcd/context/url.html)
#
51Tao
2019-04-10 22:47:22 +08:00
find . -type f -name "*.md" -exec perl -pi -e 's#OLDSTR#NEWSTR#g' {} \;

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/552615

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX