Skip to content

fix(interpreter): correct left-to-right redirect ordering for fd dup + file combos#863

Merged
chaliy merged 3 commits intomainfrom
fix/issue-853-redirect-ordering
Mar 27, 2026
Merged

fix(interpreter): correct left-to-right redirect ordering for fd dup + file combos#863
chaliy merged 3 commits intomainfrom
fix/issue-853-redirect-ordering

Conversation

@chaliy
Copy link
Copy Markdown
Contributor

@chaliy chaliy commented Mar 27, 2026

Summary

Closes #853

  • Fixes result=$(cmd 2>&1 >file) which incorrectly captured empty string instead of stderr
  • Adds fd-table model for redirect processing when DupOutput and file redirects are mixed
  • Corrects dev_null tests that asserted old (incorrect) behavior for >&2 2>/dev/null patterns

What

Bash processes redirects left-to-right, building an fd table where each dup copies the current target of the source fd. For 2>&1 >file:

  1. 2>&1 — fd2 = copy(fd1) = capture pipe
  2. >file — fd1 = file

So stderr goes to the capture pipe (result) and stdout goes to the file.

The old implementation mutated stdout/stderr strings sequentially — 2>&1 merged stderr into stdout, then >file wrote the merged string to the file, losing the fd identity.

How

  • When redirects contain both DupOutput and file redirects, use a new apply_redirections_fd_table method that builds an abstract fd table first, then routes original stdout/stderr based on the final mapping
  • Fast path preserved: when no mixed dup+file redirects exist, the original single-pass logic runs unchanged
  • Updated two dev_null tests that tested the old buggy behavior (echo error >&2 2>/dev/null should output to stderr in real bash, not suppress it)

Tests

  • redirect_2_to_1_then_file_in_cmdsub — core reproduction from issue
  • redirect_2_to_1_then_file_outside_cmdsub — same pattern without command substitution
  • redirect_file_then_2_to_1 — reverse order (>file 2>&1 sends both to file)
  • test_dev_null_stderr_redirect / test_dev_null_append_stderr — corrected to test proper fd semantics
  • Full test suite passes (2500+ tests, 0 failures)

chaliy added 3 commits March 27, 2026 01:48
…+ file combos

Closes #853 — `result=$(cmd 2>&1 >file)` now correctly captures stderr
in result and writes stdout to file.

The old approach processed redirections by mutating stdout/stderr strings
sequentially, which broke when DupOutput and file redirects were mixed.
`2>&1` would merge stderr into stdout, then `>file` would write the
merged string to the file — losing the fd identity.

New approach: when DupOutput and file redirects coexist, build an fd
table (fd1/fd2 targets) left-to-right — dup operations copy the current
target — then route original stdout/stderr based on the final fd table.

Also fixes dev_null tests that were asserting the old incorrect behavior
for `echo error >&2 2>/dev/null` (which in real bash sends output to
stderr, not /dev/null, because `>&2` copies fd2 before `2>/dev/null`
redirects it).
console 0.15.11→0.16.3, insta 1.46.3→1.47.0, simd-adler32 0.3.8→0.3.9
@chaliy chaliy merged commit 4bcff08 into main Mar 27, 2026
23 checks passed
@chaliy chaliy deleted the fix/issue-853-redirect-ordering branch March 27, 2026 02:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: result=$(cmd 2>&1 >file) redirect ordering incorrect

1 participant