Building your own shell using Rust
joshmcguigan.com
joshmcguigan.com
I wrote this blog post to document my process of building a simple shell using Rust. I learned a lot about how shells, terminal emulators, and the OS interact by going through this exercise, so I hope this is useful to others as well.
Feel free to reach out if you have any questions.
If you really want job control, a path, environmental variables, and all the things that make a shell a shell, you have to be using exec() or execvp() https://doc.rust-lang.org/std/process/struct.Command.html#me... . Otherwise all you've done is wrap an existing shell that does all the work for you, and that was an immediate fail when we had to a make a shell in my undergrad systems course.
An easy check is the use the command "echo $SHELL". If that spits out anything besides literally "$SHELL", you're farming out.
All that said, Rust's exec() is listed a unix specific, so if you're on Windows, I guess you're stuck.
I created a demo in the Rust playground [0] which shows that there is no implicit environment variable expansion. Also, the source for `std::process:Command` [1] looks to be calling into libc to perform a fork/exec.
That said, this is rather new territory for me, so let me know if I'm missing something here.
[0] : https://play.rust-lang.org/?version=stable&mode=debug&editio... [1] : https://github.com/rust-lang/rust/blob/master/src/libstd/sys...
All of this is of course Unix specific, on Windows it uses `CreateProcess`.
This could be by adding some text to clarify that this doesn’t use a shell, or maybe changing the examples to not imply one is used. It just depends.
[0]: https://github.com/kkawakam/rustyline [1]: https://github.com/redox-os/liner
However I'm not adverse adding emacs shortcuts if anyone can recommend a good guide for which keys do what.
Lesser known fact: you can also redefine which keys you want to raise SIGINT, SIGQUIT and SIGTSTP with.
It is inspired by fish
https://nixpulvis.com/ramblings/2018-10-15-building-a-shell-...
I really like the idea of syntax highlighting before the user presses enter.
Any reason you are writing your own posix parser and readline implementation, rather than using existing Rust crates?
As for the POSIX parser specifically, I love grammars, and want to support multiple, and building one in LALRPOP is t too bad. Also I looked at conch-parser, but didn't want to use its AST, and decided to go this route.
I have been using the termion crate, and may have another PR to contribute. I have somewhat ambitious goals for the readline like library though.
ANSI, and the other standards are large and somewhat unwieldy though, and there are times it would be nice to do away with it all.
As for features, there's a number of things that you could argue for being implemented in either place. One feature I feel is a good fit for the shell for example is saving and being able to recall and/or pipe previous commands, while copy paste might be implemented in both.