Hi all, author here. I'm not sure of the rules around self promotion so I want to point out that I didn't submit this, but I'm happy to see that others are enjoying it.
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.
For future reference, it's fine to submit your own stuff as long as you don't overdo it. For things that can be tried out, there's also a special Show HN category: https://news.ycombinator.com/show
I've never used Rust, but looking at the code, and reading https://doc.rust-lang.org/std/process/struct.Command.html , is std::process:Command just farming out to bash? I ask, because the examples don't specify a full path, so that implies something else is doing the PATH search, like bash. Because of this, and the semantics, it looks like it's equivalent to a system() function in other languages.
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'm not confident enough to say this for sure, but I think you are off base.
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.
It will use `execvp` (which automatically reads the PATH variable, no shell required) if you use features that require it (like `before_exec` which runs a block of code between `fork` and `exec), but it generally prefers `posix_spawnp` (Which also uses PATH). The relevant code is here: https://github.com/rust-lang/rust/blob/7d3b9b1640611c52eb949....
All of this is of course Unix specific, on Windows it uses `CreateProcess`.
If you or anyone else would like to file a bug, that’d be great: we should make this more clear in the docs. I’m about to jump on a plane or I’d just do it; a bug will make sure I get back around to it eventually.
The internal implementation of Command is using libc::execvp() on unix and CreateProcessW on windows. In windows case, it's searching the executable in the PATH manually first to match the semantics of unix.
If you look at the examples in the first link you posted, you can see to farm out to an existing shell, they're explicitly invoking "sh". There would be no reason to do that if Command always farmed out to another shell.
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.