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

Posted

技术标签:

【中文标题】如何将包含斜杠的变量传递给 sed【英文标题】:How to pass a variable containing slashes to sed 【发布时间】:2015-03-03 11:07:21 【问题描述】:

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

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

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

我想把它传递给sed

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

但是我得到了错误。我该如何规避这个问题?

【问题讨论】:

不,这不是错误的重复标记。这个问题是关于sed 中的pass a variable,它显然需要使用双引号并使用不同的分隔符,因为变量可能包含斜杠。如果变量包含逗号,则其他答案将无法正常工作。 【参考方案1】:

使用备用正则表达式分隔符sed 允许您使用任何分隔符(包括控制字符):

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

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

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

^[ 是通过同时按 Ctrl-V-3 键入的。

【讨论】:

不起作用。我尝试 sed -i "s~blah~$var~g file" 并得到:“sed -e expression #1, char 70: unterminated `s' command”。我已经确认罪魁祸首是 $var 中的斜线。这个解决方案的变体到处都是,它们都不起作用。 sed 最近更新了吗?我在 Ubuntu 14.04.4 LTS 上使用 v4.2.2。 这取决于$var的值是什么 不像@PaulEricson 观察到的那样与 ~ 一起工作,但仍然与 | 一起工作 不要为我工作。我得到sed: -e expression #1, char 17: unknown option to `s'(***.com/a/27788661/860878 工作) 似乎不需要最后一个“~”(在 g 之后),至少对于 AWS Amazon Linux(基于 CentOS)【参考方案2】:

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

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

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

sed "s#$var#replace#g" 

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

这适用于变量不包含空格的情况

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

使用上面的内容更明智,因为我们有兴趣仅替换该变量中的任何内容,而不是双引号整个命令,这可能导致您的 shell 插入任何可能被认为是 shell 的特殊 shell 字符的字符.

【讨论】:

不起作用。我尝试 sed -i "s~blah~$var~g file" 并得到:“sed -e expression #1, char 70: unterminated `s' command”。我已经确认罪魁祸首是 $var 中的斜线。这种解决方案的变体到处都是,但没有一个起作用。 sed 最近更新了吗?我在 Ubuntu 14.04.4 LTS 上使用 v4.2.2。 @PaulEricson 我无法在任何可用的 Ubuntu 上重现此内容。如果您的$var 包含~,您显然需要选择不同的分隔符。 “未终止”错误听起来像您的 $var 包含换行符;您可以通过反斜杠转义值中的每个换行符来修复它,但我认为这不是完全可移植的。这基本上与值中的斜线问题无关。 @PaulEricson 哦,您的引用不正确,您不应该在引号内包含文件名。 sed -i "s~blah~$var~g" file 仅在实际 sed 脚本周围加上引号。【参考方案3】:

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

sed 语句的一般形式是

*address* *action*

其中 address 可以是正则表达式范围或行号范围(或为空,在这种情况下 action 将应用于每个输入行)。比如

sed '1,4d' file

将删除第 1 到 4 行(address 是行号范围 1,4actiond 删除命令);和

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

将在正则表达式ick 上的第一个匹配项和文件末尾之间的任何行上用bar 替换第一次出现的foo地址 是范围@987654331 @ 并且 actions 替代命令 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

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

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

在第二个。

【讨论】:

【参考方案4】:

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

var=/Users/Documents/name/file perl -pe 's/\Q$ENVvar/replace/g' $file
-p逐行读取输入,处理后打印该行 \Q 引用以下字符串中的所有元字符(此处显示的值不需要,但如果值包含 [ 或其他一些特殊的正则表达式值,则需要)

【讨论】:

对于 Stack Exchange 中数十个“在 sed 表达式中使用变量”问题的唯一普遍有用的答案。其他一切都有效地“逃避任何对 sed 特殊的东西”,考虑到变量和 sed 的可变性,这实际上是无用的。【参考方案5】:

纯 bash 答案:使用 parameter expansion 反斜杠转义变量中的任何斜杠:

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

【讨论】:

这是一个好方法,因为您并不总是知道哪些字符包含该变量。因此,如果有疑问,您始终可以转义 sed 分隔符。例如: sed "s:$var//:/\\::replace:g" $file 美丽。使我的一些重命名脚本更加简洁。 今天学到了一些很棒的东西,谢谢。应该是公认的答案。 对这里使用的模式进行了一些澄清:$parameter/pattern/string。所以,在这种情况下,参数是var,模式是/\/,字符串是\\/。模式的所有实例都被替换,因为模式以 / 开头。 @josh,因此模式的前导斜杠实际上并不是要替换的模式的一部分。【参考方案6】:

另一种方法,虽然比 anubhava 的答案更丑陋,但使用另一个 sed 命令转义 var 中的所有反斜杠:

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

那么,这将起作用:

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

【讨论】:

以上是关于如何将包含斜杠的变量传递给 sed的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 sed 插入包含斜杠的字符串? [复制]

sed命令反斜杠的转义

你如何 grep 一个包含斜杠的字符串?

sed命令替换字符包含斜杠,引号的处理方法

shell脚本如何把反斜杠替换成斜杠反斜杠,比如2014\/5\/10变成2014/5/10,急用谢谢!

Wordpress 路径不包含斜杠