
Built a custom Mini-Shell in Go: Exploring process management and background jobs
Hello r/sideprojects
I have been exploring systems programming and recently built a custom shell entirely in Go to understand how process management works under the hood. I wanted to share my experience and get some feedback on the implementation.
While the basic loop of a shell (read, parse, execute) is simple, managing background processes and file descriptors introduced some interesting challenges.
Here is a breakdown of what I implemented and the technical hurdles:
- Process Management: Getting background jobs to run without hanging the main terminal was a challenge. I had to ensure proper redirection to
os.DevNullso background processes could detach correctly. - File Descriptors and Concurrency: I ran into bugs related to file descriptor leaks and concurrent execution when handling complex commands. Designing a modular architecture helped isolate these issues.
- Signal Handling: Implementing custom signal handling (like catching SIGINT in the parent shell while allowing foreground children to exit) was necessary to prevent the shell from closing unexpectedly.
- Environment: The project includes a multi-stage Dockerfile for a reproducible setup.
- Run using Docker: docker run -it kunaldev1oper/mini-shell:latest
You can find the source code and architecture documentation here: https://github.com/Kunal-deve1oper/mini-shell
A quick terminal recording of it in action is here: https://asciinema.org/a/1145072
I would appreciate any code reviews, suggestions on idiomatic Go usage, or feedback on how the process management could be improved.