Skip to content

Chapter 6 of 8

Arrays, Strings, Substitutions, and Arithmetic

Bash supports both indexed arrays and associative arrays (dictionaries). Indexed arrays are declared with arr=(one two three) or by element with arr[0]=one, and individual elements are accessed with \({arr[0]}. All elements are accessed with \){arr[@]} (each as a separate word) or \({arr[*]} (joined into one word), and the element count is \){#arr[@]}. New elements are appended with arr+=(four five). Iteration over indices and values together uses \({!arr[@]} to enumerate the indices: for i in "\){!arr[@]}"; do echo "\(i=\){arr[i]}"; done. Associative arrays require Bash 4 and are declared with declare -A m=([key1]=val1 [key2]=val2); keys come from \({!m[@]} and the length is \){#m[@]}.

The expansions covered in the variables chapter apply naturally to strings held in scalar variables and elements of arrays. Substrings are extracted with ${var:offset:length}, prefixes and suffixes are removed with #, ##, %, and %%, and replacement uses / for the first match, // for all, and the # and % anchors for the start and end. Case conversion uses \({var^^} and \){var,,}. To join an array into a single delimited string, set IFS locally and use "\({arr[*]}", or pipe through printf '%s\n' "\){arr[@]}" | paste -sd , for arbitrary joining.

Arithmetic in Bash is handled by the $(( ... )) expansion, which supports the usual operators: +, -, *, /, %, ** for power, bitwise operators, and the ternary. Inside (( ... )) you can use C-style syntax and assign back to variables, as in ((count++)), and the command form returns 0 when the expression's result is non-zero, making if (( a < b )); then ...; fi a natural integer test. To safely coerce a string to an integer while refusing non-digits, use base-10 notation: n=\(((10#\)s)) errors on trailing garbage instead of silently treating it as octal. All Bash arithmetic is integer-only; for floating-point comparison you must fall back to awk or bc, e.g. awk -v a=1.5 -v b=1.4 'BEGIN{exit !(a>b)}'.

Two substitution forms deserve their own mention. Command substitution — using a command's output as a value — uses $(command), the modern and easily nestable form, rather than the legacy backticks `command` (which nest poorly and behave inconsistently inside double quotes). Process substitution goes further, exposing a command's input or output as a filename referring to a /dev/fd/N pipe: diff <(sort a) <(sort b) is the classic example, replacing temporary files with on-the-fly pipes.

All chapters
  1. 1Foundations of Bash Scripting
  2. 2Variables, Expansion, Quoting, and Strict Mode
  3. 3Conditionals and Tests
  4. 4Loops and Iteration
  5. 5Functions, Sourcing, and Command-Line Arguments
  6. 6Arrays, Strings, Substitutions, and Arithmetic
  7. 7Input/Output, Redirection, and File Handling
  8. 8Process Control, Scheduling, and Robust Practices

Drill it

Reading is not remembering. These come from the Bash Scripting For Automation deck:

Q

What is Bash?

Bash (Bourne Again SHell) is a Unix shell and command language written as a free software replacement for the Bourne shell (sh). It is the default login shell o...

Q

What file extension is conventionally used for Bash scripts?

.sh. While not strictly required for execution, .sh signals intent and lets tooling treat the file as a shell script.

Q

What must the first line of an executable Bash script be?

A shebang line, e.g. #!/usr/bin/env bash or #!/bin/bash, which tells the kernel which interpreter to invoke.

Q

What command makes a script file executable?

chmod +x script.sh (or chmod 755 script.sh).