Desk Clarity

A field guide to everyday digital problems.

Developer tools / Practical guide

Bash Redirection Order Changes Where Stderr Goes: Trace the Descriptor Copy

Redirections are applied from left to right.

By ON Lab2 min readSources checked November 10, 2026 (KST)

Redirections are applied from left to right. Duplicating stderr from stdout copies its current destination; a later stdout redirection does not retroactively move that stderr destination.

Reproduce the behavior safely

Run this self-contained fixture in an empty temporary directory, separate from your project. Shell examples create only named fixture files there. JavaScript examples use local values and send no network requests.

emit() { printf 'out\n'; printf 'err\n' >&2; }
emit > both.txt 2>&1
{ emit 2>&1 > only-out.txt; } > captured.txt
printf 'both: '; tr '\n' ',' < both.txt; printf '\n'
printf 'only stdout: '; cat only-out.txt
printf 'earlier stdout destination: '; cat captured.txt
test "$(cat only-out.txt)" = out
test "$(cat captured.txt)" = err
test "$(wc -l < both.txt | tr -d ' ')" = 2

Observed local output

both: out,err,
only stdout: out
earlier stdout destination: err

Why the result changes

In the first command, stdout points at both.txt before stderr is duplicated, so both streams reach that file. In the second, stderr first copies the enclosing group output destination, captured.txt. Stdout then moves to only-out.txt. The fixture supplies that outer destination explicitly so the otherwise terminal-bound error can be inspected as data.

Choose and verify the correction

Write down descriptors one and two and update their destinations in command order. Use command >log 2>&1 when both should share the opened log. Use separate redirections when each stream needs a separate destination. Choose append versus overwrite deliberately: the fixture overwrites only files in an empty temporary directory. Inspect real wrapper, pipeline and group redirections before assuming the short command is the whole routing configuration.

Limits and next checks

Descriptor routing does not guarantee chronological ordering of independently buffered application output. Adding tee or process substitution introduces more processes and their own completion and buffering rules. This guide does not solve multi-stream chronological logging. It explains the earlier destination boundary that must be correct before that separate problem is investigated.

Related: A Bash Script Exits Zero After Failed Checks: Preserve and Aggregate Status.

Isolated fixture executed on macOS on November 10, 2026 (KST), with GNU bash, version 3.2.57(1)-release (arm64-apple-darwin26). The observed output verifies this example, not every application or runtime.

Sources & further reading