Shell scripts become fragile when a list is stored as one space-separated string, because a filename or label containing spaces can turn into several arguments. Bash arrays preserve each value as a separate element while still allowing the script to append, count, look up, and remove entries.
Indexed arrays use numeric positions beginning at zero and suit ordered values such as file paths or command arguments. Associative arrays use named keys and suit lookups where a label such as db is clearer than a numeric position.
Quoted "${files[@]}" expansion passes each array element as one word, so db backup.log remains a single loop value. Removing an indexed element leaves a gap instead of renumbering the later entries, while "${#files[@]}" reports the number of elements that still exist.
Related: How to use variables in Bash scripts
Related: How to use parameter expansion in Bash
Related: How to loop over files in Bash
#!/usr/bin/env bash set -euo pipefail files=("app.log" "db backup.log")
Parentheses create an indexed array whose first element has index 0.
files+=("web.log")
The += operator adds an element without replacing the existing values.
printf 'first file: %s\n' "${files[0]}" printf 'file count: %s\n' "${#files[@]}" for file in "${files[@]}"; do printf 'check <%s>\n' "$file" done
An unquoted ${files[@]} expansion can split db backup.log and change the arguments received by the loop body or another command.
declare -A owners=( [app]="alice" [db]="maria" ) printf 'db owner: %s\n' "${owners[db]}"
declare -A creates an associative array whose keys are names rather than numeric positions.
unset 'files[1]' printf 'remaining count: %s\n' "${#files[@]}" for file in "${files[@]}"; do printf 'keep <%s>\n' "$file" done
The quotes prevent pathname expansion from interpreting the brackets before unset receives the subscript. Removing index 1 leaves index 2 unchanged.
#!/usr/bin/env bash set -euo pipefail files=("app.log" "db backup.log") files+=("web.log") printf 'first file: %s\n' "${files[0]}" printf 'file count: %s\n' "${#files[@]}" for file in "${files[@]}"; do printf 'check <%s>\n' "$file" done declare -A owners=( [app]="alice" [db]="maria" ) printf 'db owner: %s\n' "${owners[db]}" unset 'files[1]' printf 'remaining count: %s\n' "${#files[@]}" for file in "${files[@]}"; do printf 'keep <%s>\n' "$file" done
$ bash -n array-demo.sh
No output means Bash parsed the file without a syntax error.
$ bash array-demo.sh first file: app.log file count: 3 check <app.log> check <db backup.log> check <web.log> db owner: maria remaining count: 2 keep <app.log> keep <web.log>