我想使用sed
转义变量中包含的字符串中所有未转义的字符,例如“&” text
。我所做的是
text='one&two\&three'
sed 's/\([^\\]\)&/\1\\&/g' <<< "${text}"
我期望输出是one\&two\&three
。但是,我得到的是
one\e&two\&three
我(尝试)做的事情:
- 搜索模式
\([^\\]\)&
应匹配任何&
不以反斜杠开头的 ,并存储&
在\1
- 替换模式
\1\\&
应该在&
和前一个字符之间放置一个反斜杠,但是\\\1&
由于某些奇怪的原因,它的作用就像
我在这里做错了什么?
答案1
你的命令失败的原因:
你做了:
sed 's/\([^\\]\)&/\1\\&/g' <<< "${text}"
[^\\]\
匹配除 之外的任何字符\
,并将其放入匹配组 1 中,然后&
匹配文字&
。因此,对于one&two\&three
,这将e
在第一个 之前匹配&
,将其放入捕获组 1 中。对于&
before ,three
这将不会按原样\
匹配&
在替换中您使用了
\1\\&
,所以输出变成one\e&two\&three
因为:\1
被替换为e
- 然后两个
\\
s 被视为单个\
。这给了我们e\
到目前为止 - 然后
&
将匹配完整匹配,即e&
不会&
像你想象的那样被转义
因此,匹配的部分 ie
e&
被替换为e\e&
\
如果您之前使用了另一个,那么您将获得所需的结果&
(因为两个\\
等于一个\
,所以您之前也需要一个&
:sed 's/\([^\\]\)&/\1\\\&/g' <<<"${text}"
由于 Ubuntu
sed
支持 ERE(扩展正则表达式),您可以使用-E
或 -选项来启用它,以便在捕获时r
摆脱s:()
sed -E 's/([^\\])&/\1\\\&/g' <<<"${text}"
替代方法:
首先,删除\
所有 s 之前的 s &
,然后\
在所有 之前添加&
:
sed -E 's/[\]+(&)/\1/g; s/&/\\&/g'
它由两个语句组成sed
:
s/[\]+(&)/\1/g
删除字符串(行)之前的所有\
s&
s/&/\\&/g
在字符串中添加\
全部(行)&
例子:
% text='one&two\&three'
% sed 's/\([^\\]\)&/\1\\\&/g' <<< "${text}"
one\&two\&three
% sed -E 's/([^\\])&/\1\\\&/g' <<< "${text}"
one\&two\&three
% sed -E 's/[\]+(&)/\1/g; s/&/\\&/g' <<<"$text"
one\&two\&three