पाठ 9 / 25

for, while and Reading Lines Safely

Loop over values, files and lines without breaking on spaces.

Iterating correctly

for item in list; do ...; done iterates over words: for f in *.csv loops over files matching a glob (each file name stays intact even with spaces, because globbing produces separate words), and for arg in "$@" loops over arguments. C-style loops count: for (( i = 0; i < 5; i++ )). while condition; do ...; done repeats while a command succeeds, and until while it fails, useful for retries. To process a file or command output line by line, use while IFS= read -r line; do ...; done < file: IFS= keeps leading and trailing spaces, and -r keeps backslashes literal. Do not use for line in $(cat file), which splits on every space and expands globs. When piping into while, note that the loop runs in a subshell in Bash, so variables set inside are lost afterwards; feed the loop with < file or < <(command) instead. break and continue control loop flow; enable shopt -s nullglob so a glob with no matches expands to nothing instead of the literal pattern.

Safe loops over files and lines

Globs and read -r handle awkward names and lines correctly.

shopt -s nullglob                    # no matches -> empty list, not literal "*.csv"
for f in /data/incoming/*.csv; do
    echo "processing: $f"
done

total=0
while IFS= read -r line; do
    [[ -z $line || $line == \#* ]] && continue   # skip blanks and comments
    total=$(( total + 1 ))
done < hosts.txt
echo "hosts: $total"                # works: the loop did not run in a subshell

# reading command output without losing variables
while IFS=, read -r user email; do
    echo "$user <$email>"
done < <(grep -v '^#' users.csv)

attempt=0
until curl -fsS https://example.com/health > /dev/null; do
    (( ++attempt >= 5 )) && { echo "giving up" >&2; exit 1; }
    sleep $(( attempt * 2 ))
done

cat | while loses your variables

cat file | while read -r line; do count=$((count+1)); done leaves count unchanged afterwards, because the loop ran in a subshell. Redirect the file into the loop instead.

त्वरित जाँच: Why is `while IFS= read -r line` preferred for reading lines?

  • It is faster than every other method
  • It reads the whole file into memory at once
  • It preserves spaces and backslashes exactly as they appear in each line
  • It sorts the lines
Answer

It preserves spaces and backslashes exactly as they appear in each line — Empty IFS keeps surrounding whitespace and -r stops backslash interpretation.