在sh脚本中使用sed时,我需要转义哪些字符?


248

采取以下脚本:

#!/bin/sh
sed 's/(127\.0\.1\.1)\s/\1/' [some file]

如果我尝试在shdashhere)中运行此命令,它将由于括号而失败,该括号需要转义。但是,我并不需要转义反斜线本身(八位位组之间,或\s\1)。这是什么规则?那我什么时候需要使用{...}[...]呢?有我要做的和不需要逃避的工作的清单吗?


1
这是一个bash函数,用于转换与SED一起使用的路径:function sedPath { path=$((echo $1|sed -r 's/([\$\.\*\/\[\\^])/\\\1/g'|sed 's/[]]/\[]]/g')>&1) } #Escape path for use with sed
user2428118 '16


Dura lex,sed sed
Nemo

Answers:


281

这里有两种解释级别:shell和sed。

在外壳程序中,单引号之间的所有内容均按字面意义进行解释,单引号本身除外。通过编写,您可以有效地在单引号之间使用一个单引号'\''(关闭单引号,一个文字单引号,打开单引号)。

Sed使用基本的正则表达式。在BRE中,为了使它们按字面意义处理$.*[\^,除内部字符集([…])外,必须在它们前面加上一个反斜杠来对字符进行引用。字母,数字和(){}+?|不能被引用(在某些实现中,您可以引用其中的一些内容)。的序列\(\)\n,和在一些实施方式中\{\}\+\?\|和其他反斜杠+字母数字具有特殊的含义。您可以不用$^在某些实现中的某些位置引用而摆脱困境。

此外,/如果要在方括号表达式之外的正则表达式中出现反斜杠,则需要先加一个反斜杠。您可以通过写一个或多个其他字符作为分隔符,例如s~/dir~/replacement~\~/dir~p。如果要将其包含在BRE中,则需要在定界符之前加反斜杠。如果您选择在BRE中具有特殊含义的字符,并且想要按字面意义包含它,则需要三个反斜杠;我不建议这样做,因为在某些实现中它的行为可能有所不同。

简而言之,适用于sed 's/…/…/'

  • 将正则表达式写在单引号之间。
  • 用于'\''在正则表达式中以单引号结尾。
  • $.*/[\]^仅在那些字符之前(但不在方括号表达式中)放在反斜杠之前。(从技术上讲,您不应该在前面加上反斜杠,]但我不知道在方括号表达式之外处理]\]有所不同的实现。)
  • 在方括号表达式中,-要按字面意义进行处理,请确保它是第一个或最后一个([abc-][-abc],不是[a-bc])。
  • 在方括号表达式中,要^使其按字面意义处理,请确保它不是第一个(使用[abc^],而不是[^abc])。
  • 要将其包含]在由方括号表达式匹配的字符列表中,请使其成为第一个字符(或^对于否定的集合,在第一个字符之后):[]abc][^]abc](不是[abc]]nor[abc\]])。

在替换文本中:

  • &并且\需要在它们前面加上反斜杠,以及定界符(通常是/)和换行符。
  • \后面跟数字有特殊含义。\在某些实现中,其后带有字母具有特殊含义(特殊字符),在某些实现中,\其后带有一些其他字符方式\cc取决于实现。
  • 在参数(sed 's/…/…/')周围加上单引号,可用于'\''在替换文本中加上单引号。

如果正则表达式或替换文本来自shell变量,请记住

  • 正则表达式是BRE,而不是文字字符串。
  • 在正则表达式中,换行符需要表示为\n(除非您有其他sed代码向模式空间添加换行符,否则换行符将永远不匹配)。但是请注意,在某些sed实现中,它将无法在方括号表达式中使用。
  • 在替换文本,&\和换行需要被引用。
  • 分隔符需要用引号引起来(但不要放在方括号表达式中)。
  • 使用双引号进行插值:sed -e "s/$BRE/$REPL/"

转义实际的通配符(*)时,可以使用双反斜杠(\\*)。示例:echo "***NEW***" | sed /\\*\\*\\*NEW\\*\\*\\*/s/^/#/
危险89

43

您遇到的问题不是由于shell插值和转义引起的-这是因为您尝试使用扩展的正则表达式语法而不传递sed -r--regexp-extended选项。

更改您的sed行

sed 's/(127\.0\.1\.1)\s/\1/' [some file]

sed -r 's/(127\.0\.1\.1)\s/\1/' [some file]

它将如您所愿地工作。

缺省情况下,sed使用基本正则表达式(例如grep样式),它将需要以下语法:

sed 's/\(127\.0\.1\.1\)[ \t]/\1/' [some file]

我又遇到了这个问题,忘了向下滚动以找到上次投票赞成的解决方案。再次感谢。
isaaclw 2014年

非常感谢。-r在我的情况下,必须添加一个选项。
HelloGoodbye 2015年

15

除非您想将shell变量插入sed表达式中,否则请对整个表达式使用单引号,因为它们会使它们之间的所有内容都按原样解释,包括反斜杠。

因此,如果您希望sed看到s/\(127\.0\.1\.1\)\s/\1/单引号引起来,并且外壳不会碰到其中的括号或反斜杠。如果您需要对shell变量进行插值,则仅将该部分放在双引号中。例如

sed 's/\(127\.0\.1\.1\)/'"$ip"'/'

这样可以避免记住双引号不能转义哪些外壳元字符的麻烦。


我想sed看看s/(127\.0\.1\.1)/...,但是按原样将其放在shell脚本中是行不通的。您在说外壳没有碰到括号似乎是错误的。我已经对问题进行了详细编辑。
熟练地

3
外壳没有碰到括号。您需要背影,因为sed需要查看它们。 sed 's/(127\.0\.1\.1)/IP \1/'失败,因为sed需要查看\(\)语法,而不是()
凯尔·琼斯

facepalm它不在手册页中,但是在我发现的一些在线手册中。对于正则表达式来说这是正常的吗,因为我从未在正则表达式库中使用过它(例如在Python中)?
熟练地

3
对于传统的Unix命令,有基本的正则表达式和扩展的正则表达式。 细节。sed使用基本的正则表达式,因此组语法需要反斜杠。Perl和Python甚至超出了扩展的正则表达式。当我四处闲逛时,我发现了一个非常有用的图表,该图表说明了当我们轻声地说“正则表达式”时,我们会想到的一个令人困惑的难题。
凯尔·琼斯

1
我还要补充一点,不能在单引号内使用的唯一字符是单引号。
enzotib 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.