The curious case of shell commands, or how "this bug is required by POSIX" (2021)
Overall reaction to the article
- Some see it as “woefully misguided” because invoking a shell is often an intentional feature, not a bug (e.g.,
popen("gzip > foo.gz")). - Others argue it’s mostly correct about real problems, even if the tone is dramatic and some examples (like Shellshock) are misclassified.
- General agreement that the writing is meandering; the useful part is the concrete experiments and examples.
system(), exec, and when shells are appropriate
- Broad agreement: avoid
system()in new code when you just want to run a specific program; useexec*()/posix_spawn()or language-level process APIs (e.g., Pythonsubprocess.run([...])). - Counterpoint:
system()exists because people do want shell features (pipelines, redirection, small utilities); removing it will just make people reimplement it badly. - One view: “If you’re sanitizing, you’re losing” — better to avoid mixing code and data than rely on ad‑hoc sanitization.
SSH and remote command execution
ssh host "cmd args"joins arguments with spaces and runs them via the user’s login shell, not necessarily POSIXsh, which breaks quoting assumptions and is considered a serious design wart.- Debate whether this behavior is “hidden” or adequately documented in
man ssh; consensus that it’s at least surprising and adds no real functionality, only risk. - Some tools/workarounds: pseudoshells that transport argv intact,
shlex.join()in Python, custom quoting helpers.
Quoting and escaping techniques
- Many examples of correct quoting:
- Bash:
printf '%q',${var@Q},printf -v. - Python:
shlex.quote,shlex.join,subprocess.Popenpipelines. - Shell helper patterns like
quote-argv() { printf '%q ' "$@"; }and--to stop option parsing.
- Bash:
- Discussion of tricky edge cases: arguments starting with
-, spaces, quotes, nested shells, and SSH layers.
Shell design, alternatives, and platforms
- Critique that traditional shells make safe string handling hard; proposals:
- New shells (e.g., YSH/Oil) with safer word evaluation, structured data (JSON/JSON8), and better
evalsemantics. - More explicit “invoke external only” builtins instead of relying on implicit
sh -c.
- New shells (e.g., YSH/Oil) with safer word evaluation, structured data (JSON/JSON8), and better
- POSIX vs Windows:
- POSIX has argv-based APIs and a well-known shell model, but still fragile.
- Windows fundamentally uses a single command-line string and program-specific parsing, making generic safe wrappers harder; referenced Rust CVE and Java behavior.