我有一个脚本,它读取文本流并生成一个 sed 命令文件,该文件稍后使用sed -f
. 生成的 sed 命令如下:
s/cid:image002\.gif@01CC3D46\.926E77E0/https:\/\/mysite.com\/files\/1922/g
s/cid:image003\.gif@01CC3D46\.926E77E0/https:\/\/mysite.com\/files\/1923/g
s/cid:image004\.jpg@01CC3D46\.926E77E0/https:\/\/mysite.com\/files\/1924/g
Run Code Online (Sandbox Code Playgroud)
假设生成sed
命令的脚本类似于:
while read cid fileid
do
cidpat="$(echo $cid | sed -e s/\\./\\\\./g)"
echo 's/'"$cidpat"'/https:\/\/mysite.com\/files\/'"$fileid"'/g' >> sedscr
done
Run Code Online (Sandbox Code Playgroud)
如何改进脚本以确保cid
字符串中的所有正则表达式元字符都被正确转义和插入?
Sté*_*las 27
要转义要s
在sed
(此处$lhs
和$rhs
分别)中的命令的左侧和右侧使用的变量,您可以执行以下操作:
escaped_lhs=$(printf '%s\n' "$lhs" | sed 's:[][\\/.^$*]:\\&:g')
escaped_rhs=$(printf '%s\n' "$rhs" | sed 's:[\\/&]:\\&:g;$!s/$/\\/')
sed "s/$escaped_lhs/$escaped_rhs/"
Run Code Online (Sandbox Code Playgroud)
请注意,$lhs
不能包含换行符。
也就是说,在 LHS 上,转义所有正则表达式运算符 ( ][.^$*
)、转义字符本身 ( \
) 和分隔符 ( /
)。
在 RHS 上,您只需要转义&
、分隔符、反斜杠和换行符(您可以通过在除最后一行 ( $!s/$/\\/
)之外的每一行的末尾插入反斜杠来实现)。
这假设你用/
在你的分隔符sed
s
的命令和你没有启用扩展的RE与-r
(GNU sed
/ ssed
/ ast
/ busybox sed
)或-E
(BSD系统,ast
最近GNU,最近busybox的)或PCREs用-R
(ssed
)或增强的RE与-A
/ -X
(ast
),它都有额外的 RE 操作符。
处理任意数据时的一些基本规则:
echo
sed
命令与sed
使用转义字符串(并使用相同sed
命令)的命令在相同的语言环境中运行很重要)$lhs
包含任何内容并采取行动)。另一种选择是使用perl
代替sed
并传递环境中的字符串,并使用\Q
/ \E
perl
regexp 运算符从字面上获取字符串:
A="$lhs" B="$rhs" perl -pe 's/\Q$ENV{A}\E/$ENV{B}/g'
Run Code Online (Sandbox Code Playgroud)
perl
(默认情况下)不会受到语言环境字符集的影响,因为在上面,它只将字符串视为字节数组,而不关心它们可能代表用户的字符(如果有的话)。使用sed
,您可以通过将所有命令的语言环境固定为C
withLC_ALL=C
来实现相同的效果sed
(尽管这也会影响错误消息的语言,如果有的话)。