# Redirection and Here-Documents — Bash / Shell Scripting

Source: https://www.skillbyai.com/en/bash/io-redirect

> Redirect standard streams and feed multi-line input to commands.

## Three standard streams

Every process starts with three open **file descriptors**: **0 stdin** (input), **1 stdout** (normal output) and **2 stderr** (errors and diagnostics). **Redirection** connects them to files: `cmd > out.txt` writes stdout to a file (truncating it), `>>` appends, `< in.txt` reads stdin from a file, `2> err.txt` redirects stderr, and **`2>&1`** sends stderr to wherever stdout currently goes. Order matters: `cmd > all.log 2>&1` captures both in the file, while `cmd 2>&1 > all.log` sends stderr to the terminal. Bash's shortcut `&> file` redirects both. **`/dev/null`** discards output. Scripts should write data to stdout and messages to stderr (`echo "warning" >&2`) so their output can be piped without mixing in log lines. A **here-document** (`<<EOF ... EOF`) feeds multiple lines to a command, with variable expansion; quote the delimiter (`<<'EOF'`) to disable expansion, and use `<<-EOF` to strip leading tabs. A **here-string** (`<<< "$var"`) feeds a single string.

## stdin, stdout and stderr

Each process has an input and two outputs; redirection points them at files or other processes.

![A process box with one arrow entering from the left and two arrows leaving on the right, one plain and one dashed, each pointing at a file icon.](assets/figures/bash/section-5-map.svg) — Figure 5.1 — The three standard streams and redirection.

## Redirection patterns

Separating, combining and discarding output.

```bash
./build.sh > build.log 2>&1          # everything into one file
./build.sh 2> errors.log              # only errors
./build.sh &> /dev/null || echo "build failed" >&2

exec 3> report.txt                    # open fd 3 for writing
echo "header" >&3
echo "row 1"  >&3
exec 3>&-                             # close it

cat > /etc/myapp/config.ini <<EOF
[server]
host = $(hostname)
port = ${PORT:-8080}
EOF

cat <<'EOF'
Literal text: $HOME and $(date) are NOT expanded here
EOF

grep -c error <<< "$log_excerpt"
```

## Errors to stderr, always

If your script prints "Starting..." to stdout, anyone piping its output into another tool gets that line mixed with the data. Send progress and errors to stderr and keep stdout for the actual result.

**Quiz:** Which command captures both stdout and stderr of build.sh in build.log?

- [x] ./build.sh > build.log 2>&1
- [ ] ./build.sh 2>&1 > build.log
- [ ] ./build.sh 2> build.log
- [ ] ./build.sh < build.log

*Answer:* ./build.sh > build.log 2>&1. Redirect stdout to the file first, then point stderr at the same place.
