将GNU sed命令移植到BSD sed

时间:2015-06-23 13:08:17

标签: regex linux bash sed freebsd

我正在将为Linux编写的shell脚本移植到FreeBSD,并且遇到了这一行:

local from_conf="$(sed -rn "s/^$1=('|\"|)(.*)\1/\2/ip" "$CONF" | tail -n 1)"

它被用作函数的一部分来从配置文件中获取属性($ CONF),因此添加实际变量值可能看起来像:

local from_conf="$(sed -rn "s/^USERNAME=('|\"|)(.*)\1/\2/ip" "/etc/msm.conf" | tail -n 1)"

在GNU sed(Ubuntu中的v4.2.2)下,这可以按要求工作,但是在BSD sed下(在FreeBSD 10.1中提供),它抱怨:

  

sed:1:“s / ^ USERNAME =('|”|)(。*)\ ...“:RE错误:空(子)表达式

它似乎是模式的('|"|)部分中的第二个管道,删除它(('|"))清除错误,我在FreeBSD上得到了所需的结果。它也出现以在Ubuntu下提供正确的结果,但由于我正在尝试在两个系统之间创建可移植的代码,我想更好地理解表达式的这一部分以及为什么它不能在BSD sed下工作。

我对原始模式(('|"|))的理解是:

匹配度:

  • 单引号(') - 例如USERNAME = '富'
  • 双引号(“) - 例如LOCALE =”bar“
  • 没什么() - 例如DELAY = 10

如何在不破坏GNU sed的情况下将此模式移植到BSD?

还有另一个元素不起作用:

sed -rn "s/^$1=('|\"|)(.*)\1/\2/ip" "$CONF"

\1是模式的一部分,在GNU sed下将插入('|\"|)的任何结果。这在BSD sed下不起作用,是否有不同的便携式符号?或者我是否必须逐字重复第一种模式?

编辑: /etc/msm.conf的内容可能如下所示:

USERNAME='foo'
LOCALE="bar"
DELAY=10
SERVER_NAME="Ben's Server"

sed -rn "s/^USERNAME=('|\"|)(.*)\1/\2/ip" "/etc/msm.conf"的预期输出应为“foo”。

2 个答案:

答案 0 :(得分:1)

这应该适用于删除的第一个捕获组

sed "s/^USERNAME=\(['\"]\)\{0,1\}\([^'\"]*\)['\"]\{0,1\}/\2/p;d" "/etc/msm.conf"

答案 1 :(得分:-2)

你的封闭脚本引用不好。消除这样的外部双引号:

    local from_conf=$(sed -rn "s/^$1=('|\"|)(.*)\1/\2/ip" "$CONF" | tail -n 1)

你应该好好去。

关于(...)问题,请使用\(\)。这是便携式符号。