Re: encountered a sed POSIX gotcha (GNU vs. BSD)
"Stephane Chazelas [email protected] [sed-users]" <[email protected]> Sun, 6 May 2018 19:53:39 +0100
| Newsgroups | gmane.editors.sed.user |
|---|---|
| Message-ID | <[email protected]> |
2018-05-06 07:31:30 -0500, Tim Chase [email protected] [sed-users]: > Encountered this one yesterday and thought I'd bring it to light. > > On a GNU system this works: > > sed -n '/pattern/{s/foo/bar/p}' > > but fails on BSD sed (tested on OpenBSD & FreeBSD) > > sed: 1: "/pattern/{s/foo/bar/p}": bad flag in substitute command: '}' > > This is actually POSIX which requires a newline or semicolon before a > close-brace: > > "The <right-brace> shall be preceded by a <newline> or <semicolon> > (before any optional <blank> characters preceding the <right-brace>)." > > http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html#tag_20_116_13_03 > > Thus on a BSD system it needs to have the extra semi-colon: > > sed -n '/pattern/{s/foo/bar/p;}' > > Unfortunately, I suspect that a lot of scripts out there depend on > the GNU-specific relaxed (but POSIX-violating) rules, so enforcing > the POSIX will likely break them. However, I also know that a number > of GNU tools respect a POSIXLY_CORRECT environment variable which > might be useful in this situation. [...] GNU sed is not violating POSIX here, a script that relies on the specific behaviour of GNU sed (of treating it as if there was a ; before the }) or for that matters on the BSD behaviour (of failing with an error, though it would be very unusual for a script to rely on a utility returning with an error) would be the ones being non-conformant. POSIX doesn't specify the behaviour for {s/x/y/} so either failing with an error, or the GNU behaviour (or any other behaviour) are valid behaviours. The GNU behaviour is a more useful one. The only problem with it is that it doesn't help you realise that your script is not portable. But it's not GNU sed's job to do that. What you're looking for is a linting tool that can spot non portable constructs in your code. You could make a "sedlint" fork of GNU sed that does that, like posh forked pdksh to make a shell that helps identify non-POSIX shell constructs, or one could write a shellcheck-like static code analysis tool to identify non-standard/portable code for sed. POSIXLY_CORRECT is to have tools align with POSIX when they don't by default. For instance, sed 's/[\t]//' is required to remove every instance of backslash and t characters per POSIX, which GNU sed doesn't do by default (and in that would not be compliant). GNU sed only does that under POSIXLY_CORRECT (otherwise it removes TAB characters instead). Here, a more sensible thing to do would be to ask FreeBSD folks to have their sed align with GNU sed, as it's a useful feature. And then, if enough implementations align with GNU sed, ask POSIX to make that into law. Here however, there's a problem in that for instance: {w file} is currently meant to write to a file called "file}" (and that's also what GNU sed does), and changing that could break backward compatibility, so it's possible that POSIX would not bother specifying a "}" that appears even without a preceding ";"/newline. They did however relax the requirement that "b foo}" should branch to a "foo}" label (which GNU sed didn't even under POSIXLY_CORRECT), so you never know. -- Stephane