Skip to content
koalaman edited this page Feb 19, 2014 · 11 revisions

To read lines rather than words, pipe/redirect to a 'while read' loop.

Problematic code:

for line in $(cat file | grep -v '^ *#')
do
  echo "Line: $line"
done

Correct code:

grep -v '^ *#' < file | while IFS= read -r line
do
  echo "Line: $line"
done

or without a subshell (bash, zsh, ksh):

while IFS= read -r line
do
  echo "Line: $line"
done < <(grep -v '^ *#' < file)

Rationale:

For loops by default (subject to $IFS) read word by word. Additionally, glob expansion will occur.

Given this text file:

foo *
bar

The for loop will print:

Line: foo
Line: aardwark.jpg
Line: bullfrog.jpg
...

The while loop will print:

Line: foo * Line: bar

Contraindications

If you want to read word by word, you should still use a while read loop (e.g. with read -a to read words into an array).

Rare reasons for ignoring this message is if you don't care because your file only contains numbers and you're not interested in good practices, or if you've set $IFS appropriately and also disabled globbing.

ShellCheck

Each individual ShellCheck warning has its own wiki page like SC1000. Use GitHub Wiki's "Pages" feature above to find a specific one, or see Checks.

Clone this wiki locally