Quoting to split into an array
Assigning `arr=( $var )` re-splits on IFS and globs. Use `read -ra` or `mapfile` for safe splitting.
Problem
`arr=( $string )` splits on whitespace AND expands globs in the value. For a string like `a *.txt c`, the array silently fills with every `.txt` file in the current directory. For a string with no spaces but containing `?`, the same surprise applies.
Bad
csv="alpha,beta,gamma"
IFS=',' arr=( $csv ) # also globs each elementGood
csv="alpha,beta,gamma"
IFS=',' read -ra arr <<< "$csv"
# To read lines of a file:
mapfile -t lines < file.txtExplanation
`read -ra` splits on `IFS` without globbing. `mapfile` (a.k.a. `readarray`) reads line-by-line and is the canonical way to load a file into an array. Neither performs pathname expansion on the values.
Related
SC2068
SC2128
When It Matters
arr=($var) splits the variable on IFS and glob-expands each piece, so a value containing a space, an asterisk, or a question mark produces an array that does not match the input. Scripts that build arrays from configuration values, environment variables, or command output hit this whenever real-world data arrives. The result is not an error, just a wrong number of elements — which surfaces much later as an argument list that is off by one.
Second Example
Note
read -a performs the split without pathname expansion, so an element containing * stays an asterisk instead of becoming a directory listing.
Exceptions
When you control the value and know it contains only whitespace-free tokens, the split form is fine — and with set -f active, globbing is off and the behaviour is fully predictable. Document that assumption where the array is built.
Faq
Q
How do I split on a character other than whitespace?
A
Set IFS for the single command: IFS=, read -r -a arr <<< "$csv". The assignment prefix applies only to that command.
Q
Why does read -a lose the last field sometimes?
A
A here-string appends a newline, so trailing empty fields behave differently than expected. For data with meaningful empty trailing fields, append a sentinel or use mapfile with a delimiter.
Q
Is there a difference between ${arr[@]} and ${arr[*]}?
A
Quoted, [@] expands to one word per element and [*] joins everything into a single word using the first character of IFS.