Sample output
northeast 150
The line 2026-01-15,northeast,widget-a,150,4500.00 is now five shell variables. $region and $units are ready for a test, a URL, or a log message, and you never started awk.
When you would reach for it
You wrote echo "$line" | read -r a b c, and every variable came out empty. A config line, a key=value pair, or one row of a CSV needs to become named variables in a script, and you want the parsing to happen in the shell rather than in three calls to cut. It is also the fix for any while read loop that counts or collects something and finds the total back at zero once the loop ends.
Gotchas
- In bash, every part of a pipeline runs in a subshell, so
sed -n 2p sales.csv | IFS=, read -r date region ...sets the variables in a child process that exits immediately. zsh runs the last stage in the current shell, which is why the same line works for some people and not others. In bash scripts,shopt -s lastpipechanges the behavior, but only while job control is off, so it does nothing at an interactive prompt unless you also runset +m. - A here-string always appends a newline, so
readreturns 0 even when the substitution produced nothing. Test the variables, not the exit status:[ -n "$region" ] || echo "no row". IFS=,is a plain split. A quoted CSV field like"Smith, J"gets cut at the comma inside the quotes. Use a real CSV parser (python3 -m csv,mlr) for anything with quoting. Empty fields are preserved, though:x,,zgives you an empty second variable, not a shifted third.- dash has no here-strings and stops with
Syntax error: redirection unexpected. That bites when a script with a#!/bin/shshebang lands on Debian or Ubuntu, where/bin/shis dash. Use#!/usr/bin/env bash. On Alpine, BusyBox ash may or may not accept<<<depending on how it was built, so install bash for predictable behavior.
Variants
$ IFS=, read -r date region product units revenue < <(sed -n 2p sales.csv)
Process substitution instead of a here-string. Same result, and it streams rather than buffering the whole output first
$ while IFS=, read -r date region product units revenue; do echo "$region $revenue"; done < <(tail -n +2 sales.csv)
Every data row, skipping the header. Variables set inside the loop are still there after done
$ IFS=, read -r -a fields <<< "$(sed -n 2p sales.csv)"; echo "${fields[3]}"
Split into a bash array instead of named variables. zsh spells the option -A, not -a