Page MenuHomeFreeBSD

sed(1): treat '}' as a command terminator in EMPTY, SUBST, and TR cases
Needs ReviewPublic

Authored by imp on Fri, Apr 24, 6:25 PM.
This revision needs review, but there are no reviewers specified.

Details

Reviewers
None
Summary

The command parser only recognized ';' and end-of-string as valid
terminators after commands within a group. A closing brace '}'
immediately following a command (e.g., '/foo/{s/foo/bar/;p}') was
rejected as "extra characters at the end of p command".

Handle '}' the same way as ';' — by jumping back to the command loop —
but without consuming it, so it is properly parsed as an ENDGROUP
command. We also need to do it for substitute as well, since that's
a separate path.

This is an extention to POSIX for more compatibility with the relaxed
criteria that gnu sed also accepts. POSIX.2024 requires the } to be
after a newline or semicolon. Earlier versions just a newline (which
dates back to V7 requiring that it stand on a line by itself).

Assisted-by: Claude (Opus 4.6 1M context)
Sponsored by: Netflix

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped
Build Status
Buildable 72525
Build 69408: arc lint + arc unit

Event Timeline

imp requested review of this revision.Fri, Apr 24, 6:25 PM
imp created this revision.

Can we get a test added for this?

Can we get a test added for this?

I added it in the next review in the series https://reviews.freebsd.org/D56622

Not sure if this is actually a bug. POSIX says:

The <right-brace> shall be preceded by a <newline> or <semicolon> (before any optional <blank> characters preceding the <right-brace>).

So I think this is more a case of "be helpful and do what you clearly meant" rather than "oops we weren't conforming"?

And indeed we do already handle the newline case correctly:

$ printf 'foo\nbar\nbaz\n' | sed -n $'/foo/{s/foo/bar/;p\n}'
bar

Not sure if this is actually a bug. POSIX says:

The <right-brace> shall be preceded by a <newline> or <semicolon> (before any optional <blank> characters preceding the <right-brace>).

So I think this is more a case of "be helpful and do what you clearly meant" rather than "oops we weren't conforming"?

It's also compatible with the way that gnu sed interprets things, and was the answer two different AI assistants gave me to the problem that I boiled down into this example.

You're likely right about strict conformance though. I'll rework the commit message to reflect this nuance.

And indeed we do already handle the newline case correctly:

$ printf 'foo\nbar\nbaz\n' | sed -n $'/foo/{s/foo/bar/;p\n}'
bar
printf 'foo\nbar\nbaz\n' | sed -n '/foo/{s/foo/bar/;p;}'

also works.

And reading the standard, and prior ones, this isn't required by POSIX. Earlier versions omitted ';'. And the V7 sed doc just says "The group of commands is terminated by a matching `}' standing on a line by itself."

Oh well I knew *that* one worked, I've run into this before even I think and added the missing semicolon, assuming it was my mistake (which it was, even if GNU sed is more friendly)