🎓 A1Learner
🔍
0 of 45 lessons completed

Bash Safe CSV Handling

Safe CSV handling is reading comma-separated rows without mangling fields. The while read loop splits each row on commas and keeps each field intact.

Split rows on commas with while read

The loop sets IFS to a comma for each read, so each row splits into a name and a city. Spaces inside a field stay put, since only commas split.

printf 'Ada,Lisbon\nBo,Oslo\n' > cities.csv
while IFS=, read -r name city; do printf '%s lives in %s\n' "$name" "$city"; done < cities.csv

Keep backslashes with -r

The -r option stops read from treating backslashes as escapes. The path prints with both backslashes still in place.

printf 'C:\\data\\notes,keep\n' > paths.csv
while IFS=, read -r path note; do printf '%s|%s\n' "$path" "$note"; done < paths.csv

A quoted comma still splits

The quoted name holds a comma, but read knows nothing about quotes. It splits at that comma too, so the row lands in three fields instead of two.

printf '"Doe, Jane",30\n' > quoted.csv
while IFS=, read -r f1 f2 f3; do printf 'f1=%s f2=%s f3=%s\n' "$f1" "$f2" "$f3"; done < quoted.csv

Example

printf 'Ada,10\r\nBo,20\r\nCy,30\n' > scores.csv
total=0
while IFS=, read -r name score || [ -n "$name" ]; do
  score=${score%$'\r'}
  printf '%s: %s\n' "$name" "$score"
  total=$((total + score))
done < scores.csv
printf 'total: %s\n' "$total"

Key points

  • IFS=,: tells read to split on commas, not on spaces.
  • -r: stops read from eating backslashes in fields.
  • Last row: add || [ -n "$name" ] so a final row with no trailing newline still runs.
  • Carriage returns: strip a trailing \r from the last field when a file came from Windows.
  • Quoted-field pitfall: a comma inside quotes still splits, so plain read cannot parse quoted CSV correctly.
  • Real parser: use a proper CSV parser for quoted fields, and keep read for simple unquoted rows.

In this example, the script first writes a scores file with Windows-style endings. The loop reads each row into a name and a score, and strips a trailing carriage return from the score. Each score prints beside its name, the running total grows, and the final line prints the total.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

Why does plain read split the quoted field "Doe, Jane" into two pieces?