Prefer `mapfile` or `read -a` over splitting output

`arr=( $(cmd) )` is unsafe. Use `mapfile -t arr < <(cmd)` for line-based output.

Problem

Building an array from `$(cmd)` unquoted suffers from the usual word-splitting and globbing problems. Filenames with spaces, glob characters, or unusual whitespace all break it.

Bad

files=( $(find . -name "*.log") )

Good

mapfile -t files < <(find . -name "*.log")

# Or, NUL-safe (works with arbitrary filenames):
mapfile -d '' files < <(find . -name "*.log" -print0)

Explanation

`mapfile -t` reads line by line without splitting on internal whitespace. The `-d ''` form reads NUL-delimited input, which is the only universally safe way to handle arbitrary filenames.

Related

SC2206

SC2068

When It Matters

arr=($(cmd)) splits the command output on IFS and then glob-expands each piece. A filename with a space becomes two elements, a filename containing * expands against the current directory, and an output line that happens to be a literal asterisk turns into every file in the working directory. This is the array equivalent of the unquoted-expansion bug, and it is common in scripts that build lists of files, branches, or container IDs.

Second Example

Note

Process substitution keeps the loop in the current shell, so the array survives after the loop — piping into a while loop would populate an array inside a subshell and lose it.

Exceptions

When the output is guaranteed to be whitespace-free tokens — numeric IDs, hashes, short flags — the split form is safe, and with set -f to disable globbing it is also predictable. Say so in a comment and disable the check on that line rather than leaving readers to guess.

Faq

Q

Is mapfile available everywhere?

A

It needs Bash 4, which excludes the Bash 3.2 that ships with macOS. On macOS either install a newer Bash or use the read -d loop, which works in Bash 3.

Q

What does the -t flag do?

A

It strips the trailing newline from each line before storing it, which is nearly always what you want.

Q

Why < <(cmd) rather than cmd |?

A

A pipeline runs the loop in a subshell, so any array you build inside disappears when the loop ends. Process substitution keeps the loop in the current shell.