Variables
Declaring and using variables in Bash, quoting rules, variable scope, readonly and environment variables, and parameter expansion.
Declaring & Using Variables
NAME="deploy"
echo $NAME # unquoted — works, but risky (see quoting below)
echo "$NAME" # quoted — the safe, correct habit
echo "${NAME}" # braces make boundaries explicit, needed for concatenation
GREETING="Hello, ${NAME}!" # concatenation via braces
No spaces around =. NAME = "deploy" is a syntax error in Bash — it’s parsed as running a command called NAME with arguments.
Quoting Rules (This Trips Up Everyone)
FILE="my file.txt"
echo $FILE # WRONG: word-splits into "my" and "file.txt" as separate arguments
echo "$FILE" # RIGHT: treated as one value, "my file.txt"
# Single vs double quotes
echo "$FILE" # variable IS expanded
echo '$FILE' # variable is NOT expanded — literal text
Rule of thumb: always double-quote variable expansions ("$VAR") unless you specifically want word-splitting/globbing to happen.
Variable Scope
GLOBAL_VAR="visible everywhere in this script"
my_function() {
local LOCAL_VAR="only visible inside this function"
echo "$LOCAL_VAR"
}
my_function
echo "$LOCAL_VAR" # empty — local variables don't leak out
Without local, a variable assigned inside a function is actually global — a common source of bugs in larger scripts.
Readonly & Exported Variables
readonly MAX_RETRIES=3
MAX_RETRIES=5 # error: readonly variable
export DATABASE_URL="postgres://localhost/mydb" # makes it visible to CHILD processes
./other_script.sh # other_script.sh can see $DATABASE_URL
A plain (non-exported) variable is only visible within the current shell — child processes (scripts you call, or subshells) won’t see it unless it’s exported.
Parameter Expansion (Defaults, Substrings, Replacement)
NAME=""
echo "${NAME:-default}" # "default" — use fallback if NAME is unset OR empty
echo "${NAME:=default}" # same, but ALSO assigns "default" to NAME
echo "${UNSET_VAR:?must be set}" # print error and exit if unset
STR="hello-world"
echo "${STR#*-}" # "world" — strip shortest match from the front
echo "${STR%-*}" # "hello" — strip shortest match from the back
echo "${STR/world/bash}" # "hello-bash" — replace first match
echo "${#STR}" # 11 — string length
Special / Built-in Variables
echo $0 # script name
echo $1 $2 # first, second positional arguments
echo $# # number of arguments passed
echo $@ # all arguments, as separate words
echo $? # exit status of the LAST command
echo $$ # PID of the current shell
echo $USER # current username (also HOME, PATH, PWD)
Production Considerations
- Always double-quote variable expansions in production scripts — unquoted variables are the single biggest source of subtle bugs (breaking on filenames with spaces, unexpected globbing).
- Use
${VAR:-default}for optional configuration with sane fallbacks instead of failing outright when a variable isn’t set. - Use
localreligiously inside functions — accidental global variables are hard to trace in larger scripts.
Quick Interview Answer
“Bash variables are untyped and assigned with no spaces around
=. Always double-quote expansions (\"$VAR\") to prevent word-splitting and globbing on values with spaces or special characters. Variables are local to the shell unlessexport-ed to child processes, and inside functions,localprevents accidentally leaking a variable into the global scope.”
Common Mistakes
- Writing
NAME = "value"with spaces around=, which is a syntax error. - Leaving variable expansions unquoted, causing word-splitting bugs on values containing spaces.
- Forgetting
localinside a function, silently polluting the global scope.
Add More Questions to This Guide
Know a question that should be here? Share it and help the community!
Open Google Form