I’m porting a shell script written for Linux to FreeBSD, and have come across this line:
local from_conf="$(sed -rn "s/^$1=('|\"|)(.*)\1/\2/ip" "$CONF" | tail -n 1)"
It’s used as part of a function to get properties out of a configuration file ($CONF), so adding in actual variable values it may look something like:
local from_conf="$(sed -rn "s/^USERNAME=('|\"|)(.*)\1/\2/ip" "/etc/msm.conf" | tail -n 1)"
Under GNU sed (v4.2.2 in Ubuntu) this works as required, however under BSD sed (as shipped in FreeBSD 10.1) it complains:
sed: 1: "s/^USERNAME=('|"|)(.*)\ ...": RE error: empty (sub)expression
It seems to be the second pipe in ('|"|)
part of the pattern, removing it ( ('|")
) clears the error, and I get the desired result on FreeBSD. It also appears to give the correct results under Ubuntu, but since I’m trying to make code that is portable between the two systems, I want to better understand this part of the expression and why it doesn't work under BSD sed.
My understanding of the original pattern ( ('|"|)
) is:
Match:
- a single quote (') — e.g. USERNAME='foo'
- a double quote (") — e.g. LOCALE="bar"
- nothing () — e.g. DELAY=10
How can I port this pattern to BSD without breaking it for GNU sed?
There’s another element that doesn’t work:
sed -rn "s/^$1=('|\"|)(.*)\1/\2/ip" "$CONF"
The \1
is part of the pattern, and under GNU sed will insert whatever the outcome of ('|\"|)
is. This doesn't work under BSD sed, is there a different, portable, notation? Or would I have to repeat the first pattern verbatim?
EDIT: The contents of /etc/msm.conf might look something like this:
USERNAME='foo'
LOCALE="bar"
DELAY=10
SERVER_NAME="Ben's Server"
The expected output of sed -rn "s/^USERNAME=('|\"|)(.*)\1/\2/ip" "/etc/msm.conf"
should be “foo
”.
This should work with the first capture group removed