If you want to learn more about writing a shell from an undergraduate coursework perspective (and far closer to how bash does things), this is a chapter entirely on writing your own shell: <a href="https://www.cs.purdue.edu/homes/grr/SystemsProgrammingBook/Book/Chapter5-WritingYourOwnShell.pdf" rel="nofollow">https://www.cs.purdue.edu/homes/grr/SystemsProgrammingBook/B...</a><p>That PDF covers the basics of making your own shell (i.e. splitting input into tokens aka using a lexer, parsing the resulting tokens aka using yacc [a token parser], I/O redirection, piping, executing commands, wildcarding, interrupts, environmental variables, history, subshell, revising what you've typed without having to retype it, etc.).<p>Every undergraduate CS major at Purdue University is required to do the infamous shell lab (essentially, recreate csh). This project really taught me how shells work. Before doing this project, I could do the minimum in shells, but now I'm fairly competent at it.
Thanks for continuing your series.<p>This is a great illustration of how non-trivial a production quality shell is.<p>Parsing input is "tricky"<p>Each builtin needs comprehensive error handling
Still missing the check for fork returning -1, which would make your waitpid() hang forever, as -1 waits on all p̶i̶d̶s̶,̶ ̶e̶v̶e̶n̶ ̶i̶n̶i̶t̶.̶ children.<p>Edit: less problematic than my original wrong guess, but still bad for a shell, which eventually supports multiple concurrent children.