tech-userlevel archive



    Date:        Sat, 2 Mar 2013 11:39:23 +0100
    Message-ID:  <>

  | Shell functions, and builtins that are meant to behave like external
  | programs, make this complicated,

Yes.  Though it is actually not an issue for builtins.   Only special
built-ins (which most of us probably really think are reserved words,
stuff like break, continue, return, exit) the vast majority of which it
makes absolutely no sense to use a variable assignment anyway, I mean,
who would ever do
                value=1 break; # ???
If you really want what that is defined to do, you'd just do
                value=1; break;   (or { } it if required).

But for regular builtins, variable assignments work just like tilities,
that is
        unset value; value=1 echo foo
works the same whether the echo used is the builtin, or /bin/echo
(or any other variant.)   valus is unset after echo is done.
But functions are different, if I make

        echo() { /bin/echo "$@"; }
and then do
        unset value; value=1 echo foo
now value is (according to the standard) required to be 1 after the
function finishes.

All of this is exactly how ksh works (try it).   You can also see it
with bash -o posix, if you have bash installed.

  | if you want to avoid forking (which is relatively expensive).

It isn't that it is expensive (that's just a side issue), it is that (some)
functions won't work correctly if the shell forks, so that cannot happen.

  | I think that's why the specification might be meant to be vague.

The specification actually isn't vague, it is just wrong.   That is, it
is not as any sane person would want it, though it was the correct thing to
put in the standard as shells (at the time) actually worked the way it is
documented (as useless as it is).

The people who believe the spec is unclear are (I think) just people who
cannot believe that the standard could possibly say what it says, as it is
so stupid (as a design) that they must have meant something else, so therefore
they must have not written what they meant correctly.   But this is all based
on the premise that they could not have rationally meant what is written, which
is incorrect - they did, as they were (correctly) documenting the way that
things actually worked (or perhaps really, didn't work).

If I write

        mycd() { cd "$1" ; echo "$var" }

and then do

        var=value mycd /home/me

then after this completes (as the standard is written) the requirement is
that the current directory of the shall is /home/me, "value" was written
to stdout, and $var = value

The cd prohibits a fork, and no doubt the cheap way to implement this leaves
the variable set after the function is done (and that's how functions were
first implemented in the old bourne shell apparently).

This is also how ksh and bash in posix mode work.

It isn't how NetBSD's shell works, nor bash in its "normal" mode, in those
the var=value part applies (just like it would if "mycd" was "ls" or any
other "utility") only to the command.   So, clearly it is possible to
implement this fairly easily (it has been done at least twice, and I suspect
many other shells do this as well).

What is vague about the standard is whether (after the function has finished)
var is exported or not - the standard doesn't say explicitly one way or the
other (ksh doesn't export it, bash in posix mode does - I think the argument
there is that it is exported to pass to the command, and nothing anywhere says
to revert that, so ...)

Of course, this question is irrlevant in a sane shell (like NetBSD's) which
ignores that part of the spec, and assigns the value only for the command
(whether it is a utility, which is the way it always works, or a function).



Home | Main Index | Thread Index | Old Index