read without -r mangles backslashes
Without `-r`, `read` interprets backslashes as line continuations and escape sequences. Always pass `-r`.
Problem
By default, `read` treats backslash as the start of an escape sequence — a line ending in `\` is joined with the next, and `\n` inside data is consumed. Almost no script wants this; the result is unexpected data corruption when input contains paths or JSON.
Bad
while read line; do
process "$line"
done < input.txtGood
while IFS= read -r line; do
process "$line"
done < input.txtExplanation
`IFS=` prevents trimming of leading/trailing whitespace; `-r` disables backslash interpretation. Together they are the safe default for line-by-line reading.
When It Matters
Without -r, read treats backslash as an escape character: it strips single backslashes and joins a line ending in a backslash with the next one. Any script that reads Windows paths, regexes, LaTeX, JSON with escaped quotes, or password files will silently corrupt its input. The corruption is invisible in the common case — most lines contain no backslash at all — so the bug reaches production and then destroys exactly the one record that had a backslash in it.
Second Example
Note
IFS= read -r line is the canonical form: -r disables escape processing, and the empty IFS stops leading and trailing whitespace being trimmed.
Exceptions
Omitting -r is only correct when you deliberately want line continuation — for example reading a config format where a trailing backslash joins lines. That is rare enough to deserve a comment plus an explicit "# shellcheck disable=SC2162".
Faq
Q
What does IFS= do in front of read?
A
It clears the field separator for that one command, which stops read from trimming leading and trailing whitespace from the line. Without it, indentation and trailing spaces are lost.
Q
Does -r affect how fields are split?
A
No. Field splitting is controlled by IFS; -r only controls whether backslash is treated as an escape character.
Q
Why does my loop skip the last line?
A
read returns non-zero when it hits end of file without a trailing newline, so the final partial line is read but the loop exits. Use while IFS= read -r line || [ -n "$line" ]; do ... done.