Skip to content
File Descriptors and Redirection
step 1/7

Reading — step 1 of 7

Learn

~3 min readI/O and Iteration

Bash's redirection isn't just > and <. The full file descriptor model lets you route any stream anywhere. Bash Cookbook treats this as essential for production scripts.

Standard streams

Every process has three open by default:

  • fd 0 (stdin) — input
  • fd 1 (stdout) — normal output
  • fd 2 (stderr) — errors
echo "hello"                 # writes to fd 1 (stdout)
echo "oops" >&2              # writes to fd 2 (stderr)
read line                    # reads from fd 0 (stdin)

Basic redirection

cmd > out.txt                # stdout to file (truncate)
cmd >> out.txt               # stdout to file (append)
cmd 2> err.txt               # stderr to file
cmd < in.txt                 # stdin from file
cmd > out.txt 2> err.txt     # split stdout and stderr

Combining streams

cmd > all.txt 2>&1           # stderr to stdout, both to file
# Common shortcut:
cmd &> all.txt               # bash-only: both to file
cmd >& all.txt               # alternative form

cmd 2>&1 | grep foo          # pipe BOTH stdout and stderr to grep
cmd 2>&1 > out.txt           # WRONG order — stderr to terminal, stdout to file
cmd > out.txt 2>&1           # CORRECT — both to file

Order matters. 2>&1 means "redirect fd 2 to whatever fd 1 currently points to" — so it must come AFTER > out.txt.

Discarding output

cmd > /dev/null              # discard stdout
cmd 2> /dev/null             # discard stderr
cmd &> /dev/null             # discard everything

Use this when you only care about the exit status:

if command -v git &> /dev/null; then
    echo "git is installed"
fi

Here-documents and here-strings

# Here-doc — multi-line literal:
cat <<EOF
Line 1
Line 2
EOF

# Here-doc with interpolation:
name="Ada"
cat <<EOF
Hello, $name
EOF

# Here-doc literal (no interpolation — quote the marker):
cat <<'EOF'
No $variable expansion here
EOF

# Here-string — single-line:
grep foo <<< "hello world foo bar"

Here-docs are great for embedded scripts, SQL, JSON. Here-strings replace echo "..." |.

Custom file descriptors

# Open fd 3 for writing to a log:
exec 3> /var/log/myscript.log

echo "info message" >&3
echo "error" >&2

exec 3>&-                    # close fd 3

Advanced — useful for scripts with multiple output channels (audit log, error log, normal output).

tee — split a stream

cmd | tee output.txt         # write to file AND stdout
cmd | tee -a output.txt      # append (don't truncate)
cmd 2>&1 | tee -a log.txt    # log everything

Useful for capturing output while still seeing it in the terminal.

Common mistakes

  • 2>&1 BEFORE >file — wrong order. stderr ends up at the terminal.
  • Confusing > with >>> truncates; >> appends. Mistakes wipe files.
  • Quoting variables in here-docs<<EOF interpolates; <<'EOF' (quoted) is literal.
  • Using cat file | cmd — useless cat. Use cmd < file or < file cmd.
  • Forgetting that exit status of a pipeline is the LAST command — without set -o pipefail, errors mid-pipeline go silent.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…