Guide Bash-Scripting Beginner

Variables

Declaring and using variables in Bash, quoting rules, variable scope, readonly and environment variables, and parameter expansion.

3 min read

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 local religiously 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 unless export-ed to child processes, and inside functions, local prevents 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 local inside 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