Reading — step 1 of 7
Learn
For processing files line by line, while read is the standard bash idiom. Far safer than for f in $(cat file) (which word-splits and is broken on spaces in names).
The classic pattern
while read -r line; do
echo "got: $line"
done < file.txt
-r— don't interpret backslashes (always use it)< file.txt— redirect file as stdin to the loopreadreturns non-zero at EOF, terminating the loop
Reading from a command
ls *.txt | while read -r f; do
echo "$f"
done
Caveat: pipelines run in subshells. Variables set inside the loop are LOST when the loop ends:
count=0
ls | while read -r f; do (( count++ )); done
echo "$count" # 0! the increment was in a subshell
Fix with process substitution:
count=0
while read -r f; do (( count++ )); done < <(ls)
echo "$count" # actual count
< <(...) makes the loop run in the parent shell. THIS PATTERN MATTERS — keep it in your toolkit.
Reading multiple fields
With CSV-like input, read splits by IFS:
echo "alice,30,engineer" | while IFS=',' read -r name age role; do
echo "$name is $age, works as $role"
done
But multiple lines:
while IFS=',' read -r name age role; do
echo "$name: $age, $role"
done < users.csv
IFS=',' is set ONLY for that read command — doesn't affect the rest of the script.
Reading the last incomplete line
If the last line lacks a trailing newline, default read skips it:
printf "a\nb\nc" | while read -r line; do echo "got: $line"; done
# only prints "got: a" and "got: b" — c is dropped
printf "a\nb\nc" | while read -r line || [[ -n "$line" ]]; do echo "got: $line"; done
# now prints all three
The || [[ -n "$line" ]] catches the partial last line.
Reading from stdin (for scripts)
while read -r line; do
echo "received: $line"
done
Reads until EOF. Useful for scripts that process piped input: cat data | ./process.sh.
When NOT to use while read
For file processing, awk is often better:
awk -F',' '{ print $1, $2 }' users.csv
For simple grepping, grep is faster than reading line-by-line in bash. Use while read when you need bash logic per line that's hard to express in awk/grep.
Common mistakes
- Forgetting
-r— backslashes get interpreted as escapes. Always use -r. - Pipeline subshell variable loss — modifications inside a piped while are invisible outside. Use process substitution.
- Skipping the last line without newline — add
|| [[ -n "$line" ]]for safety. for line in $(cat file)— word-splits on whitespace, breaks on multi-word lines. Always use while read.- Read with mistuned IFS — set IFS in the same command (
while IFS=',' read ...) not globally.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…