tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

external versions of sh built-in utilities

An off-list message from Paul Goyette reminded me that I had been
intending to send an email about this topic for a while, but I keep
forgetting, so before  that happens again ...

Now what was this message about ????

Oh ... builtins.   We know the shell has a whole lot of commands built in.

Some are (almost) shell syntax, but are regarded as built-in commands,
these are the so-called "special" built-ins (like break, continue,
exit, export, '.', ... posix defines 15, to which we add "local")
about which I will say no more since they are irrelevant to this message.

Then there are another set that are built in (mostly) because scripts
use them a lot, and they run much faster if the command can just be
implemented in the shell, rather than needing to fork/exec a separate
process.   This is things like test, echo, printf, kill, pwd, (even true and
false).  (The built-in kill is actually slightly enhanced, for job control,
over the external one, so it almost comes in the next category, but doesn't).

This (previous) set of commands all have analogues that are found
somewhere in $PATH (/bin/test /usr/bin/printf ...)   This set (whose number
is indeterminate, as any shell can have anything built in if it chooses)
are also irrelevant to this message.

That leaves the rest.   These are the commands that have to be built into
the shell or they won't do anything useful.   This is commands like
cd, ulimit, wait, times, bg, fg, jobs, ...  there are actually quite a lot
(you can read the sh man page to see the complete set, just omit the
ones in the other two categories.)   These have no external command
equivalent (because such a thing would be useless).

This leads to the crux of the matter - I have been told that POSIX
actually requires that all of the commands in this third category (actually
all the sh built-in commands, except the special built-ins) have an
executable that can be subject of an execvp(2) call.  The second group
already have that, so it is only the third that matter here.

Yes, I know, it is more or less insane, as none of the commands in question
can actually do anything particularly useful as a separate process (eg:
wait can only wait for children of the current process, if we create a new
process to run it, it, by definition, has no children, hence ...)

I am also (currently anyway) unable to confirm this requirement, I have
looked, but cannot find anything that says this in POSIX - but that means
nothing, there has been other text that I have read there, and know is there,
that when I go looking for I simply cannot find again.   It is a very
big document!

Apparently the standard way to conform with this requirement (if it exists,
it is possible it once did, and then sanity took over - as unlikely as that
seems in the standards community, sometimes they do the right thing) is to
create a small script

	#! /bin/sh
	$(basename $0) "$@"

(or something quite similar to that), and then install that script somewhere
in $PATH (probably /usr/bin, though /usr/useless would do ...) and link
it to all the names for the shell built-ins that have no other file system
command equivalent, so this script would become (amongst many other names)
/usr/bin/cd and when run like

	execl("/usr/bin/cd", "cd", "/some/path", 0);

it would run a shell (the #!/bin/sh) in which $0 would be "cd" and
"$@" (just $1 in this case) would be /some/path, so the shell would
	cd /some/path

and then promptly exit (with the exit status from the internal cd command,
probably indicating an error in this particular case.)

So should we do something like this?    That is, if we can find somewhere
in the POSIX spec that requires it.


Home | Main Index | Thread Index | Old Index