Note: The “cd” command must be a built-in command in the shell, since it must call chdir(2) inside the shell process; it must affect the “current directory” internal state of the shell process. Therefore, “cd” cannot be a separate external binary.
You could sort of do it via Bernstein chaining. If we call this substitute command 'notcd' then you'd invoke it like `exec notcd /some/path sh` and then continue your work in the subshell.
The shell would then have to also have a mechanism to pass all local state such as command history, local non-exported variables (including shell functions), open file descriptors, currently running jobs, etc. to the subshell.
We're talking about bootstrapping to more usable tools, not about whether this hack fully replaces the standard feature. 'cd' certainly comes before command history, for example.
Incidentally you could take the same approach to some other shell built-ins, like redirection. Instead of `cat foo >outfile`, define a program named '>' and then say `> outfile cat foo`. (Assuming the initial bare-bones shell parses '>' as just another ordinary character, not special.) Use these until you've written a more featureful shell.
It might be interesting to figure out a design for a shell where this decentralized approach works well and does not feel like a kludge -- I imagine you'd have to change some deeper aspects of the OS design to really make it work.
There are a couple of problems with that design. Firstly, if the program crashes for any reason, you don’t have a shell to fall back on, unless you run the debugger as your shell, like ITS did back in the 1960s. Secondly, you can’t have more than one job running at the same time, or even any suspended jobs. And even ITS (again) has subjobs.
If your shell crashes, same problem. And the shell is a bigger program. This issue seems pretty orthogonal. Again, I was never saying this is a better way to design a shell for everyday use, unless maybe with a lot of complementary design decisions changed to go with it.
> Secondly
Why couldn't you spawn jobs like `& do-the-job` in this style? Admittedly I don't remember much about Unix job handling.