Step 1 of 5 · Reading · ~3 min
Learn
Arrays and Scripts
Arrays
Bash arrays are the language's late admission that word-splitting wasn't a data structure. They hold real lists — elements with spaces, empty elements, the works — if you use the (admittedly baroque) syntax exactly. The payoff: correct handling of filenames and arguments, the two lists every script actually manages.
The syntax, precisely
fruits=("apple" "kiwi fruit" "cherry") # literal — note element 2 contains a space
fruits+=("mango") # append
echo "${fruits[0]}" # apple — index from 0, braces REQUIRED
echo "${#fruits[@]}" # 4 — length
Braces are non-negotiable: $fruits[0] without them means "$fruits then the literal text [0]" (bash expands $fruits as element 0 — a trap that almost works, the worst kind).
The one expansion to memorize: "${arr[@]}"
for f in "${fruits[@]}"; do
echo "-> $f"
done
Output — four lines, "kiwi fruit" intact. That quoted-[@] form is the entire reason arrays exist: it expands to one word per element, boundaries preserved, no matter what the elements contain. Every variation loses:
${fruits[@]}unquoted → word-splits: "kiwi fruit" becomes two items"${fruits[*]}"→ ONE word containing everything, space-joined
So: iterating, passing to commands, forwarding — always "${arr[@]}". (Its twin for script arguments is "$@", same semantics, which is why the Functions lesson called it the only correct forwarding form.)
Filling arrays from data
read -r -a nums # split ONE input line into an array
mapfile -t lines # slurp ALL of stdin, one element per LINE
files=(*.txt) # glob straight into an array — spaces safe
read -a for a line of fields, mapfile -t for lines (the -t trims newlines), glob-into-array for files. These three cover effectively every "get a list into bash" situation — and each replaces a word-splitting hack that breaks on real data.
Iterating with indices, when you must
for i in "${!nums[@]}"; do # ${!arr[@]} = the list of indices
echo "$i: ${nums[$i]}"
done
Rarely needed (element iteration covers most work), but ${!arr[@]} is the piece people can't find when they need position numbers.
String keys: associative arrays
Bash 4 added maps, and they need an explicit declaration:
declare -A ages
ages["ada"]=36
echo "${ages[ada]}" # 36
for k in "${!ages[@]}"; do # ${!arr[@]} gives the KEYS here
echo "$k -> ${ages[$k]}"
done
The -A is load-bearing. Without it the name is an ordinary indexed array and the subscript is evaluated as arithmetic, so a non-numeric key quietly becomes index 0 and every key you set overwrites the same slot. Lowercase declare -a is the indexed kind.
Your exercise: Largest Number
Read a line of numbers and print the biggest -- the tracker pattern, with an array intake. The starter fills nums for you; the scan is yours.
Graded essentials, all old friends wearing brackets. Seed the running maximum from a real element rather than from 0, because the hidden case is all-negative and a zero seed would win it. Compare with (( )), where > means greater-than -- inside [[ ]] the same symbol would compare the numbers as text and rank 9 above 10. And iterate over the quoted "${nums[@]}", the expansion that keeps your list a list. The other classic miss is arithmetic: a maximum tracked in one variable and printed from another prints the seed.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…