如何使用 sed 转义非转义字符?

如何使用 sed 转义非转义字符?

我想使用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&不会&像你想象的那样被转义
  • 因此,匹配的部分 iee&被替换为e\e&

    \如果您之前使用了另一个,那么您将获得所需的结果&(因为两个\\等于一个\,所以您之前也需要一个&

    sed 's/\([^\\]\)&/\1\\\&/g' <<<"${text}"
    

    由于 Ubuntused支持 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

相关内容