02 · Variables & Data Types¶
🎥 Video walkthrough¶
Bash doesn't have real "data types" the way Python or Java do — everything is stored as a string by default, and arithmetic contexts reinterpret strings as integers. Understanding this is the key to not being surprised later.
Declaring and using variables¶
name="Ada" # NO spaces around = — this is critical
age=30
echo "$name is $age years old"
# Ada is 30 years old
name = "Ada" # WRONG: bash parses this as running a command `name`
# with arguments `=` and `Ada"` — syntax error
Variable names are case-sensitive, can contain letters, digits, and underscores, and can't start with a digit.
Reading a variable: always quote it¶
food="fried rice"
echo $food # risky: word-splits on spaces
echo "$food" # safe: prints "fried rice" as one value
Without quotes, Bash performs word splitting on the variable's value
before passing it along — a value with spaces can silently turn into multiple
arguments. Quoting "$var" is the single most important habit in this whole
curriculum.
Numbers and arithmetic¶
There's no native "integer" type — arithmetic happens inside $(( ... )) or
(( ... )), which treat the content as numeric expressions:
a=5
b=3
echo $((a + b)) # 8
echo $((a * b)) # 15
echo $((a / b)) # 1 — integer division, no decimals!
echo $((a % b)) # 2 — remainder
((a++)) # increment a by 1 (a is now 6)
echo "$a" # 6
For decimals, Bash has no built-in support — reach for bc or awk:
Quoting rules — the part everyone trips on¶
| Quote style | Variable expansion? | Word splitting? | Use for |
|---|---|---|---|
"double quotes" |
Yes | No | almost everything |
'single quotes' |
No (literal) | No | fixed text, no $var inside |
| no quotes | Yes | Yes (dangerous) | rarely — only literals with no spaces |
name="World"
echo "Hello, $name" # Hello, World (expands)
echo 'Hello, $name' # Hello, $name (literal, no expansion)
echo Hello, $name # works here, but fragile — avoid the habit
Read-only and unsetting variables¶
readonly PI=3.14159
PI=3 # error: PI: readonly variable
count=5
unset count
echo "${count:-not set}" # not set (default-value expansion, see below)
Environment variables vs. shell variables¶
local_var="only visible in this shell"
export SHARED_VAR="visible to child processes too"
bash -c 'echo "$SHARED_VAR"' # prints the value — export propagates it
bash -c 'echo "$local_var"' # prints nothing — not exported
export marks a variable so it's copied into the environment of any child
process the shell starts (like scripts it runs, or other programs).
Useful default/built-in variables¶
echo "$0" # the script's own name/path
echo "$1" # first positional argument (Module 5 covers these in depth)
echo "$#" # number of positional arguments passed to the script
echo "$$" # PID of the current shell
echo "$?" # exit code of the last command (Module 9 covers this in depth)
Parameter expansion basics (defaults)¶
greeting="${name:-friend}" # if $name is unset or empty, use "friend"
echo "$greeting"
: "${PORT:=8080}" # if PORT is unset, SET it to 8080
echo "$PORT"
How It Actually Works¶
Bash variables are stored in the shell's own process memory as a flat table
of name/value string pairs — there's no int, float, or boolean type at the
storage layer. age=30 stores the two-character string "30". Arithmetic
contexts like $(( )), let, and [[ ... -lt ... ]] don't change that
storage; they just ask bash's arithmetic evaluator to parse the string as a
number for the duration of that one expression, using base-10 by default
(a leading 0 triggers octal, 0x triggers hex).
exporting a variable doesn't change how it's stored inside bash — it flags
that name/value pair to be copied into the environment block that gets
handed to every child process at fork()/execve() time. That's why a
non-exported variable is invisible to a subshell script you invoke, and why
each child gets its own private copy: environment variables are passed by
value at process-creation time, not shared memory, so a child mutating its
copy of $PATH never affects the parent shell.
Parameter expansion (${name}, ${name:-default}) happens during the
shell's word expansion pass, which runs in a fixed order every time a
command line is parsed: brace expansion, tilde expansion, parameter/variable
expansion, arithmetic expansion, and command substitution all happen before
word splitting and globbing. That's why quoting matters — expansions inside
double quotes still happen, but the result is protected from the later
word-splitting and pathname-expansion steps.
🔀 See this in another language¶
Exercise¶
Write bmi.sh that sets weight_kg=70 and height_m=1.75 as variables,
computes BMI using awk (since it needs decimals), and prints a sentence
like Your BMI is 22.86. Then add a third variable unit="metric" and print
it using double quotes to show correct expansion.