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

Bol*_*boa 88 bash sed

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

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

var="/Users/Documents/name/file"
Run Code Online (Sandbox Code Playgroud)

我想把它传递给sed:

sed "s/$var/replace/g" "$file"
Run Code Online (Sandbox Code Playgroud)

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

anu*_*ava 159

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

sed "s~$var~replace~g" $file
Run Code Online (Sandbox Code Playgroud)

  • 不起作用 我尝试sed -i“ s〜blah〜$ var〜g file”并得到:“ sed -e表达式#1,字符70:未终止的s命令”。我已经确认罪魁祸首是$ var中的斜线。这种解决方案的变种无处不在,但没有一个起作用。sed最近更新了吗?我在Ubuntu 14.04.4 LTS上的v4.2.2上。 (2认同)
  • 这取决于 `$var` 的值是什么 (2认同)
  • 正如@PaulEricson 所观察到的,不适用于 ~,但仍然适用于 | (2认同)
  • 最后一个“~”(g之后)似乎不需要,至少对于AWS Amazon Linux(基于CentOS) (2认同)
  • 我终于在这里找到了答案...谢谢!! (2认同)

gle*_*man 48

一个纯粹的bash答案:使用参数扩展来反斜杠 - 转义变量中的任何斜杠:

var="/Users/Documents/name/file"
sed "s/${var//\//\\/}/replace/g" $file
Run Code Online (Sandbox Code Playgroud)

  • 这里使用的模式有一些清晰度:$ {parameter / pattern / string}`。因此,在这种情况下,参数为`var`,模式为`/ \ /`,字符串为`\\ /`。模式的所有实例都将替换,因为模式以`/`开头。 (5认同)
  • 这是一个好方法,因为您并不总是知道哪些字符包含该变量。因此,如果有疑问,您始终可以转义 sed 分隔符。例如: sed "s:${var//:/\\:}:replace:g" $file (2认同)
  • @josh,因此模式的前导斜杠实际上并不是要替换的模式的一部分。 (2认同)
  • @glennjackman是的,尽管在您引用的文档中他们说“如果模式以'/'开头,则模式的所有匹配都将替换为字符串。” 我遵循他们的惯例,将其作为模式的一部分进行讨论。虽然谈论它似乎是一种尴尬的方式,但在我看来,语法一开始就相当尴尬。 (2认同)
  • 诚实应该是公认的答案。谢谢 (2认同)

Bol*_*boa 27

另一种方法,虽然比anubhava的答案更丑陋,但是通过var使用另一个sed命令来逃避所有反斜杠:

var=$(echo "$var" | sed 's/\//\\\//g')
Run Code Online (Sandbox Code Playgroud)

那么,这将有效:

sed "s/$var/replace/g" $file
Run Code Online (Sandbox Code Playgroud)


rep*_*ero 12

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

var="/Users/Documents/name/file"
Run Code Online (Sandbox Code Playgroud)

你可以使用适合场合的octothorpe角色(或任何其他不易/于使用的角色)

sed "s#$var#replace#g" 
Run Code Online (Sandbox Code Playgroud)

要么

sed 's#$'$var'#replace#g'
Run Code Online (Sandbox Code Playgroud)

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

要么

sed 's#$"'$var'"#replace#g'
Run Code Online (Sandbox Code Playgroud)

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


cho*_*oba 5

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

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


tri*_*eee 5

这是一个古老的问题,但是这里没有任何答案s/from/to/会详细讨论操作。

sed声明的一般形式是

*address* *action*
Run Code Online (Sandbox Code Playgroud)

其中address可以是正则表达式范围或行号范围(或为空,在这种情况下,该操作将应用于每个输入行)。所以举个例子

sed '1,4d' file
Run Code Online (Sandbox Code Playgroud)

将删除第1至4行(地址是行号范围1,4,而动作ddelete命令);和

sed '/ick/,$s/foo/bar/' file
Run Code Online (Sandbox Code Playgroud)

将在regex上的第一个匹配项与文件末尾之间的任何行上foo用替换第bar一个匹配项ick地址是范围/ick/,$,而动作是replace s命令s/foo/bar/)。

在这种情况下,如果ick来自变量,则可以

sed "/$variable/,\$s/foo/bar/"
Run Code Online (Sandbox Code Playgroud)

(请注意,请使用双引号而不是单引号,以便外壳程序可以对变量进行插值,并且必须在双引号内使用文字美元符号进行引号),但是如果变量包含斜杠,则会出现语法错误。(shell扩展变量,然后将结果字符串传递给sed;,因此sed只能看到文字文本-它没有shell变量的概念。)

解决方法是使用不同的定界符(显然,您需要能够使用变量值中不会出现的字符),但是与这种s%foo%bar%情况不同,如果要使用其他定界符,还需要在定界符前加反斜杠比默认分隔符/

sed "\\%$variable%,\$s/foo/bar/" file
Run Code Online (Sandbox Code Playgroud)

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

sed "/${variable//\//\\/}/,\$s/foo/bar/" file
Run Code Online (Sandbox Code Playgroud)

或者,如果您使用其他外壳,请尝试

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

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

sed '\%1/2%,$s/foo/bar/' file
Run Code Online (Sandbox Code Playgroud)

在第一种情况下,以及

sed '/1\/2/,$s/foo/bar/' file
Run Code Online (Sandbox Code Playgroud)

在第二。