Hi zsh-workers,
On this machine (macOS 15.8.2 x86_64, /bin/zsh 5.9 (x86_64-apple-darwin24.0), Apple build), a heredoc or here-string attached to a NON-FIRST member of a pipeline does not override the implicit pipe on stdin. Instead, the command receives the upstream pipeline output CONCATENATED with the heredoc body (in that order, no separator). bash and /bin/sh on the same machine implement the standard semantics (explicit redirection wins) correctly.
Minimal repro:
% printf 'PIPE-CONTENT' | cat <<'EOF' HEREDOC-CONTENT EOF PIPE-CONTENTHEREDOC-CONTENT # zsh 5.9 actual (concatenated)
# expected / bash & /bin/sh actual: HEREDOC-CONTENT
Probe matrix (run via python subprocess with exact argv control):
1. zsh -c, multi-line, heredoc on last stage -> concatenated 2. leading "export PATH=..." line + same command -> concatenated 3. eval '<cmd>' wrapper -> concatenated 4. zsh script file (non -c mode) -> concatenated 5. 3-stage pipeline, heredoc on last member -> concatenated 6. heredoc on the MIDDLE member -> concatenated 7. heredoc on the FIRST member (cat <<EOF | cat) -> correct (body only) 8. standalone heredoc (no pipe) -> correct 9. empty upstream output (printf '' | cat <<EOF) -> body only (proves in-order concatenation, not duplication) 10. here-string: printf X | cat <<< 'H' -> concatenated 11. bash -c / bash file / /bin/sh -c -> correct in all cases
The heredoc body always arrives as data: a line `echo SHOULD-NOT-RUN` inside the body is delivered verbatim to the reader's stdin, never executed.
Reproduction rate: 100%. Caveat: this is the Apple-shipped zsh binary; I could not compare against a pristine upstream build on this machine (no Homebrew zsh installed), so an Apple-specific patch cannot be ruled out.
Context / practical impact: discovered while debugging false failure alerts in an agent runtime that executes commands through zsh -c. The pattern
openclaw cron list --json | python3 - <<'EOF' ... EOF
feeds the piped JSON to python as *source code* (dying with `NameError: name 'true' is not defined` at the first bare true) instead of executing the heredoc script. Interpreter-from-stdin pipelines (`python3 -`, `bash -s`) are the dangerous shape: upstream pipe text becomes executable code.
Happy to test patches or gather more diagnostics.
-- 孤客 <feiniaovip@xxxxxxxxx>
|