13 SC2207
GfEW edited this page 2024-11-28 15:59:26 +01:00

Prefer mapfile or read -a to split command output (or quote to avoid splitting).

Problematic code:

array=( $(mycommand) )

Correct code:

If it outputs multiple lines, each of which should be an element:

# For bash 4.4+, must not be in posix mode, may use temporary files
mapfile -t array < <(mycommand)

# For bash 3.x+, must not be in posix mode, may use temporary files
array=()
while IFS='' read -r line; do array+=("$line"); done < <(mycommand)

# For ksh, and bash 4.2+ with the lastpipe option enabled (may require disabling monitor mode)
array=()
mycommand | while IFS="" read -r line; do array+=("$line"); done

If it outputs a line with multiple words (separated by spaces, other delimiters can be chosen with IFS), each of which should be an element:

# For bash, uses temporary files
IFS=" " read -r -a array <<< "$(mycommand)"

# For bash 4.2+ with the lastpipe option enabled (may require disabling monitor mode)
array=()
mycommand | IFS=" " read -r -a array

# For ksh
IFS=" " read -r -A array <<< "$(mycommand)"

If the output should be a single element:

array=( "$(mycommand)" )

Rationale:

You are doing unquoted command expansion in an array. This will invoke the shell's sloppy word splitting and glob expansion.

Instead, prefer explicitly splitting (or not splitting):

  • If you want to split the output into lines or words, use mapfile, read -ra and/or while loops as appropriate.
  • If the command output should become a single array element, quote it.

This prevents the shell from doing unwanted splitting and glob expansion, and therefore avoiding problems with output containing spaces or special characters.

Exceptions:

If you have already taken care (through setting IFS and set -f) to have word splitting work the way you intend, you can ignore this warning.

Another exception is the wish for error handling: array=( $(mycommand) ) || die-with-error works the way it looks while a similar mapfile construct like mapfile -t array < <(mycommand) doesn't fail and you will have to write more code for error handling.