Send both stdout and stderr to one log — the 2>&1 ordering trap
A cron job should append BOTH its stdout and its stderr to run.log, but the line below still lets error messages escape to the terminal (and cron mails them). The order of the redirections is the bug.
Constraints: both streams must end up in run.log; also show how to discard stderr, and how to feed a literal block on stdin with a here-doc.
myjob 2>&1 > run.log
Fix the ordering, then add the discard and here-doc forms.
Redirections apply left to right, so myjob 2>&1 > run.log first points stderr at wherever stdout is now (the terminal), then moves stdout to the file — errors escape. Put the file first: myjob > run.log 2>&1. Discard errors with 2>/dev/null; feed literal stdin with a here-doc, cmd <<'EOF' … EOF (quoted tag = no expansion).
- ✗Writing
2>&1before the file, so stderr copies the terminal, not the file - ✗Thinking
2>&1swaps the descriptors rather than duplicating one onto the other - ✗Believing the shell resolves redirections all at once instead of left to right
- →What does the shorthand
&>(or&>>) do, and why prefer the explicit form? - →Why does a quoted here-doc tag like
<<'EOF'disable variable expansion inside it?
Solution
2>&1 is not a swap but a duplication: "make fd 2 point to wherever fd 1 points right now." Redirections are read left to right, so order is decisive.
# BUG: stderr first copies the current stdout (terminal), then stdout goes to file
myjob 2>&1 > run.log # errors stay on the terminal
# RIGHT: stdout → file first, then stderr duplicates the already-redirected stdout
myjob > run.log 2>&1 # both streams in the file (to append: >> run.log 2>&1)
Discarding stderr and feeding a literal stdin:
myjob 2>/dev/null # errors to the black hole, stdout untouched
cmd <<'EOF' # here-doc; a quoted tag = no $ or ` expansion
line one
line two
EOF
Bottom line: in myjob > run.log 2>&1, by the time 2>&1 runs stdout already points at the file, so stderr is duplicated onto the file. Swapping the order breaks it because fd 1 still points at the terminal at that instant.