如何将包含斜杠的变量传递给 sed

如何将包含斜杠的变量作为模式传递给 sed

例如,如果我有以下变量:

var="/Users/Documents/name/file"

我想把它传给 sed,就像这样:

sed "s/$var/replace/g" "$file"

然而,我得到了错误。我怎样才能规避这个问题?

102581 次浏览

使用替代的正则表达式分隔符,因为 sed允许您使用任何分隔符(包括控制字符) :

sed "s~$var~replace~g" $file

如上所述,我们可以使用控制字符作为分隔符,以及像:

sed "s^[$var^[replace^[g" file

其中通过按 Ctrl-V-3键打出 ^[

或者在 bash shell 中,你可以使用这个 sed\03作为分隔符:

d=$'\03'
sed "s${d}$var${d}replace$d" file

纯 bash 回答: 使用 参数展开反斜杠转义变量中的任何斜杠:

var="/Users/Documents/name/file"
sed "s/${var//\//\\/}/replace/g" $file

另一种方法是使用另一个 sed命令转义 var中的所有反斜杠,尽管这种方法比阿努巴瓦的回答更难看:

var=$(echo "$var" | sed 's/\//\\\//g')

那么,这将会奏效:

sed "s/$var/replace/g" $file

在 sed 中使用 /作为分隔符将与替换后的变量中的斜杠冲突,因此您将得到一个错误。避免这种情况的一种方法是使用另一个分隔符,该分隔符与该变量中的任何字符都是唯一的。

var="/Users/Documents/name/file"

您可以使用适合场合的 octothorpe 字符(或任何其他非 /的字符,以方便使用)

sed "s#$var#replace#g"

或者

sed 's#$'$var'#replace#g'

当变量不包含空格时,这是合适的

或者

sed 's#$"'$var'"#replace#g'

使用上面的命令是明智的,因为我们只对替换变量中的任何字符感兴趣,而不是双引号整个命令,因为双引号整个命令可能导致您的 shell 与任何可能被认为是 shell 特殊字符的字符相互干扰。

使用 Perl,其中变量是头等公民,而不仅仅是扩展宏:

var=/Users/Documents/name/file perl -pe 's/\Q$ENV{var}/replace/g' $file
  • -p逐行读取输入行并在处理后打印该行
  • \Q引用了下面字符串中的所有元字符(这里提供的值不需要引用,但是如果值包含 [或一些其他正则表达式特殊的值,则必须引用)

这是一个老问题,但是这里没有一个答案详细讨论除 s/from/to/以外的操作。

sed语句的一般形式是

*address* *action*

其中 地址可以是正则表达式范围或行号范围(或空,在这种情况下,开拍应用于每个输入行)。举个例子

sed '1,4d' file

将删除第1行到第4行(地址是行号范围 1,4,而 开拍d delete 命令) ;

sed '/ick/,$s/foo/bar/' file

将在正则表达式 ick的第一次匹配到文件结束之间的任何一行上用 bar替换第一次出现的 foo(地址是范围 /ick/,$,而 开拍s替代命令 s/foo/bar/)。

在此上下文中,如果 ick来自变量,则可以执行

sed "/$variable/,\$s/foo/bar/"

(请注意使用双引号而不是单引号,这样 shell 就可以插入变量,并且需要在双引号中引用字面的美元符号)但是如果变量包含斜杠,就会出现语法错误。(shell 展开变量,然后将结果字符串传递给 sed; 因此 sed只能看到文本——它没有 shell 变量的概念。)

解决办法是使用不同的分隔符(显然你需要能够使用一个不能出现在变量值中的字符) ,但与 s%foo%bar%不同的是,如果你想使用不同于默认 /的分隔符,你还需要在分隔符前面加一个反斜杠:

sed "\\%$variable%,\$s/foo/bar/" file

(在单引号中,一个反斜杠显然就足够了) ; 或者您可以分别转义该值中的每个斜杠。这种特殊的语法只适用于 Bash:

sed "/${variable//\//\\/}/,\$s/foo/bar/" file

或者如果您使用不同的 shell,请尝试

escaped=$(echo "$variable" | sed 's%/%\\/%g')
sed "s/$escaped/,\$s/foo/bar/" file

为了清楚起见,如果 $variable包含字符串 1/2,那么上面的命令将等效于

sed '\%1/2%,$s/foo/bar/' file

在第一种情况下,

sed '/1\/2/,$s/foo/bar/' file

在第二个。

您可以使用任何字符作为分隔符来给出 sed命令。例如,使用字符 #作为 sed的分隔符,您可以将 cat替换为 dog,如下所示:

sed -i s#cat#dog#g test.txt

如果你使用变量

sed -i s#$var#replace#g $file