I had similar thoughts some time ago but came to a very different conclusion: anything the shell can do a programming language could do just as well, given the right interface. The fact that languages don't make it easy to spawn subprocesses safely doesn't mean that they couldn't do so. The right solution is making it both convenient <i>and</i> safe to do shell-like things from within a real programming language. So I made sure that Julia does this right:<p><a href="https://julialang.org/blog/2012/03/shelling-out-sucks" rel="nofollow">https://julialang.org/blog/2012/03/shelling-out-sucks</a><p><a href="https://julialang.org/blog/2013/04/put-this-in-your-pipe" rel="nofollow">https://julialang.org/blog/2013/04/put-this-in-your-pipe</a>
<i>"I'll just escape it" is a typical and yet unacceptable response to this.</i><p>There seems to be some sort of "cult" (for lack of better term) around this mentality of "it's too hard so don't do it", which unfortunately only makes things worse overall. Escaping rules are well-defined (they must be, by necessity), and sooner or later you're going to have to do something involving it; not to mention the important superset of things to keep in mind when writing code, of which escaping is only a fraction: the general principle of "consider <i>all</i> input". Always assume that all 256 values of a byte can and will show up in any external input, and plan accordingly.
Because the shell is a generalized engine for executing things, and because magic defines textfiles as candidate executables nominating either the shell or a shell-exec binary to interpret them, and because system() jacks all of this to say you can invoke a shell with all its awesome to invoke scripts which invoke a binary to parse them.<p>If the shell was only rsh, and if the set of binaries you can invoke was constrained, and if the network and system calls were accessed through strace() barriers which limited what you could do.. We might have less problems. Except that in the end, people don't code or script for secure execution so the context of 'what harm can I do from here' turns out to be a lot wider than many people think.
The premise is faulty. Subprocesses are fine, it is the POSIX shell that should be avoided. Or any interpreted language.
Smallest tool for the job.<p>Use exec* calls, right options for your process handling class and there is no problem.<p>As a bonus feel free to spawn/fork your current application.<p>Linking pipes and file descriptors is also not that hard. (Though they are a cruddy that may be nicer to wrap in something like 0mq.)