为什么转义字符和正则表达式不能很好地与 sed 命令配合使用?



就我而言,我想使用 sed 命令将一行分隔到单词,如下所示,尽管我应该都可以工作。

[heping@Laputa:~]$echo "abc  def    gks       dps" | sed "s/s+/n/g"
abc  def    gks       dps
[heping@Laputa:~]$echo "abc  def    gks       dps" | sed "s/s{1,}/n/g"
abc  def    gkn       dpn
[heping@Laputa:~]$echo "abc  def    gks       dps" | sed "s/ {1,}/n/g"
abcndefngksndps
[heping@Laputa:~]$echo "abc  def    gks       dps" | sed "s/ {1,}/:/g"
abc:def:gks:dps
[heping@Laputa:~]$echo "abc  def    gks       dps" | sed "s/ +/:/g"
abc  def    gks       dps

但实际上,只有一个有效。

[heping@Laputa:~]$echo "abc  def    gks       dps" | sed "s/ {1,}/:/g"
abc:def:gks:dps

正则表达式中的s字符集和+特殊字符似乎不能很好地与 sed 命令配合使用。并且n不被识别为新行。谁能告诉我为什么或提供一些线索。谢谢。

sed 匹配基本正则表达式,而元字符+来自扩展正则表达式。POSIX 字符类[[:space:]]的速记s仅适用于某些 sed(例如 GNU sed)作为扩展。同样,n在某些 sed 中只能用作"换行符"的含义,而在任何 sed 中,您可以使用反斜杠后跟文字换行符。你在脚本周围使用双引号 (") 而不是单引号 (') 会将其暴露给 shell,因此需要额外的反斜杠转义 - 始终在字符串或脚本周围使用单引号,除非您对双引号有非常特殊的需求(例如,让变量扩展),并且只使用双引号,除非您对 none 有非常具体的需求(例如,允许通配符扩展)。

在任何 POSIX sed 中做你想做的事情是:

$ echo 'abc  def    gks       dps' | sed 's/[[:space:]][[:space:]]*/
/g'
abc
def
gks
dps

但这适用于 GNU sed(请注意为+启用 ERE 的-E- GNU sed 和 OSX/BSD sed 支持,但在这两个 sed 中,只有 GNU sed 支持sn):

$ echo 'abc  def    gks       dps' | sed -E 's/s+/n/g'
abc
def
gks
dps

有几个问题。首先,sed默认使用基本的正则表达式,无法识别+。对扩展正则表达式使用-E修饰符,这样做。

其次,sed不识别n,但你可以使用ANSI C引用来使bash理解它。但是,如果您只使用n,则sed模式中只有一个换行符,因此您必须转义换行符才能sed字面上使用它;因此,您需要\进行转义,n换行符,总共三个反斜杠。

最后,s作为一个字符类也不被原版sed识别(但它在Linux发行版使用的GNUsed上可用)。如果您需要与例如OSX(或brew install gnu-sed)兼容,请使用文字空格。

echo "abc  def    gks       dps" | sed -E $'s/ +/\n/g'
# => abc
#    def
#    gks
#    dps

最新更新