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 do 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. kre