我正在将一个为 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 error: empty (sub)expression
它似乎是模式的 ('|"|)
部分中的第二个管道,删除它( ('|")
)清除错误,并且我在 FreeBSD 上得到了想要的结果。它还似乎在 Ubuntu 下给出了正确的结果,但由于我正在尝试编写可在两个系统之间移植的代码,我想更好地理解表达式的这一部分以及为什么它不不能在 BSD sed 下工作。
我对原始模式 ( ('|"|)
) 的理解是:
匹配:
- 单引号 (') — 例如用户名='foo'
- 双引号 (") — 例如 LOCALE="bar"
- nothing () — 例如延迟=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
”。
最佳答案
这应该与删除的第一个捕获组一起使用
sed "s/^USERNAME=\(['\"]\)\{0,1\}\([^'\"]*\)['\"]\{0,1\}/\2/p;d" "/etc/msm.conf"
关于regex - 将 GNU sed 命令移植到 BSD sed,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31003678/