svn commit: r211609 - head/tools/regression/bin/sh/builtins

Jilles Tjoelker jilles at stack.nl
Mon Aug 23 21:58:52 UTC 2010


On Mon, Aug 23, 2010 at 12:33:14AM -0700, Brian Somers wrote:
> On Sun, 22 Aug 2010 11:04:30 +0000 (UTC) Jilles Tjoelker <jilles at FreeBSD.org> wrote:
> > Author: jilles
> > Date: Sun Aug 22 11:04:30 2010
> > New Revision: 211609
> > URL: http://svn.freebsd.org/changeset/base/211609

> > Log:
> >   sh: Add a test for breaking from a loop outside the current function.

> >   It is unwise to rely on this but I'd like to know if this would break.

> > Added:
> >   head/tools/regression/bin/sh/builtins/break3.0   (contents, props changed)

> > Added: head/tools/regression/bin/sh/builtins/break3.0
> > ==============================================================================
> > --- /dev/null	00:00:00 1970	(empty, because file is newly added)
> > +++ head/tools/regression/bin/sh/builtins/break3.0	Sun Aug 22 11:04:30 2010	(r211609)
> > @@ -0,0 +1,15 @@
> > +# $FreeBSD$
> > +
> > +# We accept this and people might rely on it.
> > +# However, various other shells do not accept it.
> > +
> > +f() {
> > +	break
> > +	echo bad1
> > +}
> > +
> > +while :; do
> > +	f
> > +	echo bad2
> > +	exit 2
> > +done

> This feature should be counted as a bug IMHO.  How can f() possibly
> know whether there's a surrounding context to break from?

If you replace f by its definition, there is an obvious meaning.

And how about a script like:
  while :; do
    f() { ...; break; ...; }
    ...
    f
    ...
  done

I will admit that there are various other shells that do not implement
this.

> Having said that, this behaviour is the same in bash except that bash
> will complain if it's asked to break when the context is wrong,
> perhaps we should complain too?

> $ bash -c 'f() { break; echo no break; }; for f in good bad; do echo $f; f; done'
> good
> $ sh -c 'f() { break; echo no break; }; for f in good bad; do echo $f; f; done'
> good
> $ bash -c 'f() { break; echo no break; }; f'
> bash: line 0: break: only meaningful in a `for', `while', or `until' loop
> no break
> $ bash -c 'f() { break 2>/dev/null; echo no break; }; f'
> no break
> $ sh -c 'f() { break; echo no break; }; f'
> no break

The System V sh and ksh93 behave the same way with break and continue
builtins outside loops.

I don't think this is very broken, and there is a limit on how many
incompatible changes I'm willing to make. This doesn't make the cut.

Warning messages to stderr mostly get lost in the noise, I don't really
like them. I do not expect people to test for failure of break and
continue, and bash even sets $? to 0 despite printing a warning. If this
error is so important as to need an error message I think should abort
the shell as well (via error(), so that "command break" will avoid
aborting).

Furthermore note that bash disables these warnings in POSIX mode.

As an aside, if breaking out of a function were to be disallowed, a
stronger approach seems possible: special builtins cannot be overridden
by functions or PATH (we currently do not implement this), so if the
parser (after alias expansion) sees a command "break" or "continue", it
must be the special builtin and a parse error could result if it is not
in a loop, or possibly a ksh93-like parse warning with -n.

-- 
Jilles Tjoelker


More information about the svn-src-all mailing list