关于如何逃避sed的各种元素,这个网站上有很多问题,但我正在寻找更一般的答案。我知道我可能想要逃避一些字符以避免shell扩展:
Bash:
- 单引号[strings] ('')用于保留引号中包含的每个字符的文字值。 [但是,]单引号之间可能不会出现
单引号,即使前面有反斜杠也是如此。- 只有当后跟美元,反引号,双引号>时,反斜杠才会保留[在双引号字符串]中的含义strong>,反斜杠或换行符。在双引号内,当后跟其中一个字符时,反斜杠将从输入流中删除。不具有特殊含义的字符前面的反斜杠不会被修改以供shell解释器处理。
sh :(我希望你没有历史扩展)
- 单引号字符串行为:与bash相同
- 用双引号括起字符可保留字面值 引号中的所有字符,美元,单引号,反斜杠除外,以及 启用历史记录扩展时,感叹号。
- 字符
dollar
和单引号在双引号中保留其特殊含义。- 反斜杠仅在后跟以下字符之一时保留其特殊含义:
$
,'
,"
,\
或换行符。 双引号可以在双倍范围内引用 引用前面的反斜杠。- 如果启用,则会执行历史记录扩展,除非使用反斜杠转义出现在双引号中的感叹号。之前的反斜杠!是不已删除。
...但是没有一个能解释为什么一旦你删除任何转义就停止工作:
sed -e "s#\(\w\+\) #\1\/#g" #find a sequence of characters in a line
# why? ↑ ↑ ↑ ↑ #replace the following space with a slash.
(
,)
,/
或+
(或[
或]
...)似乎没有特殊意义,要求他们逃脱才能工作。地狱,即使直接通过Python调用命令也会使sed无法正常工作,尽管联机帮助页似乎没有说清楚这一点(不管怎么说,当我搜索反斜杠时)。
$ lvdisplay -C --noheadings -o vg_name,name > test
$ python
>>> import os
>>> #Python requires backslash escaping of \1, even in triple quotes
>>> #lest \1 is read to mean "byte with value 0x01".
>>> output = os.execl("/bin/sed", "-e", "s#(\w+) #\\1/#g", "test")
(Output remains unchanged)
$ python
>>> import os
>>> output = os.execl("/bin/sed", "-e", "s#\(\w\+\) #\\1\/#g", "test")
(Correct output)
$ WHAT THE HELL
Have you tried using jQuery? It's perfect and it does all the things.
答案 0 :(得分:4)
如果我理解正确,你的问题不是关于bash / sh,而是关于默认使用的正则表达式sed:BRE。
另一个[=任何但点,星号,插入符号和美元] BRE元字符需要反斜杠才能赋予它们特殊的含义。原因是最早版本的UNIX
grep
不支持这些。
应该对(..)
分组进行转义,以赋予其特殊含义。与+
相同,否则sed将尝试匹配它们,因为它们是文字字符串/字符。这就是为什么你的s#\(\w\+\) #...#
应该被转义的原因。更换部件不需要转义,所以:
sed 's#\(\w\+\) #\1 /#'
应该有用。
sed
通常可以选择使用extended regular expressions(现在使用?
,+
,|
,()
,{m,n}
);例如GNU sed有-r
,那么你的单行可能是:
sed -r 's#(\w+) #\1 /#'
我在这里粘贴了一些示例,可以帮助您了解正在发生的事情:
kent$ echo "abcd "|sed 's#\(\w\+\) #\1 /#'
abcd /
kent$ echo "abcd "|sed -r 's#(\w+) #\1 /#'
abcd /
kent$ echo "(abcd+) "|sed 's#(\w*+) #&/#'
(abcd+) /
答案 1 :(得分:1)
您所观察到的是正确的。使用基本>时,需要转义某些字符,例如?
,+
,(
,)
,{
,}
strong>正则表达式。
引用sed manual:
基本和扩展正则表达式之间的唯一区别是 在几个字符的行为:
‘?’
,‘+’
,括号和大括号 (‘{}’
)。 虽然基本正则表达式要求转义 你希望它们在使用扩展时表现为特殊字符 正则表达式,如果你希望它们匹配a,你必须转义它们 字面意思。
(强调我的。)但是,当使用扩展正则表达式时,不需要对它们进行转义,除非匹配文字字符(如最后一行引用中提到的上面。)
答案 2 :(得分:1)
如果您想要一般性答案,
所以你有以下场景;
# Match a literal question mark
echo '?' | grep \?
# or equivalently
echo '?' | grep "?"
# or equivalently
echo '?' | grep '?'
# Match a literal asterisk
echo '*' | grep \\\*
# or equivalently
echo '*' | grep "\\*"
# or equivalently
echo '*' | grep '\*'
# Match a backreference: any character repeated twice
echo 'aa' | grep \\\(.\\\)\\1
# or equivalently
echo 'aa' | grep "\(.\)\\1"
# or equivalently
echo 'aa' | grep '\(.\)\1'
正如您所看到的,单引号在大多数情况下可能最有意义。
如果要嵌入需要反斜杠引用的语言,则必须添加另一组反斜杠,或者避免调用shell。
正如其他人所指出的那样,扩展正则表达式遵循稍微不同的语法,但一般模式是相同的。最重要的是,为了尽量减少来自shell的干扰,请尽可能使用单引号。
对于文字字符,您可以通过使用字符类来避免一些反斜视。
echo '*' | grep \[\*\]
# or equivalently
echo '*' | grep "[*]"
# or equivalently
echo '*' | grep '[*]'
答案 3 :(得分:-1)
FreeBSD sed
,也用于Mac OS X,使用-E
代替-r
扩展正则表达式。
因此,要使其可移植,请使用基本的正则表达式。例如,在扩展正则表达式模式下,+
必须在基本正则表达式模式下用\{1,\}
替换。
在基本以及扩展正则表达式模式下,FreeBSD sed
似乎无法识别必须用\w
替换的[[:alnum:]_]
(参见man re_format
)。
# using FreeBSD sed (on Mac OS X)
# output: Hello, world!
echo 'hello world' | sed -e 's/h/H/' -e 's/ \{1,\}/, /g' -e 's/\([[:alnum:]_]\{1,\}\)$/\1!/'
echo 'hello world' | sed -E -e 's/h/H/' -e 's/ +/, /g' -e 's/([[:alnum:]_]+)$/\1!/'
echo 'hello world' | sed -E -e 's/h/H/' -e 's/ +/, /g' -e 's/(\w+)$/\1!/' # does not work
# find a sequence of characters in a line
# replace the following space with a slash
# output: abcd+/abcd+/
echo 'abcd+ abcd+ ' > test
python
import os
output = os.execl('/usr/bin/sed', '-e', 's#\([[:alnum:]_+]\{1,\}\) #\\1/#g', 'test')
要将单引号用作sed
正则表达式的一部分,同时保留sed
正则表达式的外部单引号,可以连接三个单独的字符串,每个字符串用单引号括起来以避免可能的shell扩展
# man bash:
# "A single quote may not occur between single quotes, even when preceded by a backslash."
# cf. http://stackoverflow.com/a/9114512 & http://unix.stackexchange.com/a/82757
# concatenate: 's/doesn' + \' + 't/does not/'
echo "sed doesn't work for me" | sed -e 's/doesn'\''t/does not/'