Skip to main content
Bash beginner Lesson 4 of 22

Bash Data Types

Learn how Bash handles strings, integers, arrays, associative arrays, and readonly variables with practical examples.

Everything Is a String

Unlike most programming languages, Bash has no strict type system. Every variable holds a string, and Bash interprets it differently depending on context — as a number in arithmetic expressions, as a path in file tests, or as plain text otherwise. Understanding this prevents a class of subtle bugs where you expect numeric behavior and get string behavior instead.

x=42
y="hello"
z=3.14

# All are strings — bash doesn't know the difference without hints
declare -p x   # declare -- x="42"
declare -p y   # declare -- y="hello"
declare -p z   # declare -- z="3.14"

declare is the keyword that adds type attributes to variables, giving Bash hints about how to treat them.

Strings

String is the default type. No declaration is needed, and strings can contain anything — whitespace, special characters, and even newlines.

first="Alice"
last="Smith"
full="${first} ${last}"
echo "$full"           # Alice Smith

# Multi-line string
message="Line one
Line two
Line three"
echo "$message"

# Heredoc — cleaner for multi-line content
message=$(cat <<'EOF'
Dear Alice,
Your account is active.
EOF
)
echo "$message"

String length:

name="Alice"
echo "${#name}"   # 5 — the # operator counts characters

Integers

Use declare -i to mark a variable as an integer. Bash then performs arithmetic on assignment rather than string concatenation. This distinction matters: without the flag, count+=5 appends the character 5 to the string; with it, count is incremented numerically.

declare -i count=10
count+=5
echo "$count"   # 15  (arithmetic addition)

count="abc"     # invalid — bash stores 0 when the string is non-numeric
echo "$count"   # 0

Without declare -i, assignments are literal string operations:

count=10
count+=5
echo "$count"   # 105  (string concatenation — not addition!)

For arithmetic without declare -i, use the $(( )) construct:

a=10
b=3
echo $(( a + b ))   # 13
echo $(( a * b ))   # 30
echo $(( a / b ))   # 3  (integer division — remainder discarded)
echo $(( a % b ))   # 1  (remainder)
echo $(( a ** b ))  # 1000 (exponentiation)

Indexed Arrays

Indexed arrays let you store ordered lists of values and refer to them by position. They are essential any time you need to process a collection of items — a list of servers to check, files to process, or arguments to pass to a command.

# Declaration and initialization in one step
fruits=("apple" "banana" "cherry")

# Or declare first, then assign
declare -a colors
colors[0]="red"
colors[1]="green"
colors[2]="blue"

# Access by index
echo "${fruits[0]}"    # apple
echo "${fruits[1]}"    # banana
echo "${fruits[-1]}"   # cherry (negative index counts from the end)

# All elements — always use [@] in double quotes
echo "${fruits[@]}"    # apple banana cherry

# Number of elements
echo "${#fruits[@]}"   # 3

# All indices
echo "${!fruits[@]}"   # 0 1 2

Adding and removing elements:

fruits+=("date")              # append a new element
fruits[1]="blueberry"         # replace element at index 1
unset fruits[2]               # remove index 2 (leaves a gap in the indices)

echo "${fruits[@]}"           # apple blueberry date
echo "${#fruits[@]}"          # 3

Slicing arrays:

letters=("a" "b" "c" "d" "e")
echo "${letters[@]:1:3}"   # b c d  (start at index 1, take 3 elements)
echo "${letters[@]:2}"     # c d e  (from index 2 to end)

Associative Arrays

Associative arrays use string keys instead of integer indices — essentially a hash map or dictionary. They are declared with declare -A (the declaration is mandatory; without it, Bash treats them as indexed arrays and the string keys are silently converted to integers).

# Must declare explicitly — unlike indexed arrays
declare -A user

user["name"]="Alice"
user["age"]="30"
user["role"]="admin"

# Access
echo "${user["name"]}"    # Alice
echo "${user[role]}"      # admin (quotes optional for simple keys)

# All values
echo "${user[@]}"         # Alice 30 admin (order is not guaranteed)

# All keys
echo "${!user[@]}"        # name age role

# Check if key exists
if [[ -v user["email"] ]]; then
  echo "email is set"
else
  echo "email not set"
fi

Iterating over an associative array:

declare -A config=(
  [host]="localhost"
  [port]="5432"
  [db]="myapp"
)

for key in "${!config[@]}"; do
  echo "$key = ${config[$key]}"
done
# host = localhost
# port = 5432
# db = myapp

readonly

readonly prevents modification after initial assignment. It is useful for defining constants at the top of a script — values that represent configuration, paths, or limits that must never be changed. If something tries to overwrite them, the script exits with an error immediately.

readonly MAX_CONNECTIONS=100
readonly -a ALLOWED_ENVS=("production" "staging" "development")

MAX_CONNECTIONS=200   # Error: readonly variable

# declare -r is equivalent
declare -r API_VERSION="v2"

nameref — Variable References (Bash 4.3+)

declare -n creates a reference to another variable by name. Its main use is writing generic functions that can operate on any variable passed in by name — particularly useful for returning arrays from functions without a subshell.

declare -A server_a=([host]="web1" [port]="80")
declare -A server_b=([host]="web2" [port]="443")

print_server() {
  declare -n ref="$1"   # ref is now an alias for the named variable
  echo "Host: ${ref[host]}, Port: ${ref[port]}"
}

print_server server_a   # Host: web1, Port: 80
print_server server_b   # Host: web2, Port: 443

Type Summary

declare flagTypeExample
(none)Stringname="Alice"
-iIntegerdeclare -i count=0
-aIndexed arraydeclare -a list=()
-AAssociative arraydeclare -A map=()
-rReadonlydeclare -r MAX=100
-xExporteddeclare -x PATH="..."
-nNamerefdeclare -n ref=varname
-lLowercase on assigndeclare -l lower
-uUppercase on assigndeclare -u upper

What’s Next

With data types covered, the next tutorial digs into operators — arithmetic, comparison, and logical operators for building real decision logic.

Frequently Asked Questions

Does Bash have real data types?
Not in the traditional sense. Every variable in Bash is a string by default. declare -i tells Bash to treat a variable as an integer for arithmetic, but it's still stored as a string internally.
What is the difference between indexed and associative arrays?
Indexed arrays use integer indices (0, 1, 2...). Associative arrays use string keys, like a hash map or dictionary. Associative arrays require declare -A.
Can Bash handle floating point numbers?
Not natively. Use the bc utility or awk for float arithmetic. Python is a better choice if your script heavily uses decimals.