Bash Variables: Create, Assign, Use and Unset

Tested on RHEL 10.2 (Coughlan)
Package bash 5.2.26-6.el10
Applies to Linux distributions with Bash installed
Privilege Normal user; no root required for the examples
Scope Bash variable assignment, naming, $var and ${var} expansion, quoting, empty vs unset, unset, readonly, common declare attributes, and a short scope overview. Includes one basic default-value example; advanced parameter-expansion operators and arrays are covered separately. Does not cover export or environment inheritance in depth.
Related guides Bash shell script tutorial
Shell scripting course hub
Short on time?Beta Get the gist of this 9-minute read in seconds, then ask follow-up questions

In this article, you'll learn how to create Bash variables, expand them with $name and ${name}, and tell the difference between unset, empty, and readonly variables.

Bash variable assignment is simple, but small differences in spacing and quoting can change how a value is interpreted. The examples use printf for predictable output — Bash echo vs printf explains when echo is enough. declare -p makes it easy to check the value and attributes Bash stored.


What Is a Bash Variable?

A Bash variable stores a value under a name such as log_dir or retention_days. Bash documentation uses the broader term parameter; a variable is one type of parameter.

Variables exist in the current shell process. Bash variables do not have fixed data types like variables in many programming languages. Values are normally treated as text, while attributes such as declare -i change how Bash handles assigned values and arithmetic.


Create and Assign Variables

Use name=value with no spaces around =. In a simple assignment, Bash expands variables, commands, arithmetic expressions, and ~, but it does not perform word splitting or filename expansion on the resulting value.

Several expansions can run in the value before it is stored:

bash
user="Ada"
home_copy=~/backup
message="Hello $user"
today=$(date +%F)
printf 'home_copy=%s message=%s today=%s\n' "$home_copy" "$message" "$today"
output
home_copy=/root/backup message=Hello Ada today=2026-09-09

$user expanded inside double quotes, ~ became your home directory, and $(date +%F) ran the command and stored its output. Filename expansion does not run on the result of a simple assignment, so an unquoted * in the assigned value is not expanded to matching filenames.

Assign a name that contains a space:

bash
name="Ada Lovelace"
printf 'name=%s\n' "$name"
output
name=Ada Lovelace

Spaces around = make Bash try to run a command named name, which fails:

bash
bash -c 'name = value'
output
bash: line 1: name: command not found

Naming rules

Variable names must start with a letter or underscore, then letters, digits, or underscores:

  • Valid: host, _private, log_dir2
  • Invalid: 2host (starts with a digit), my-var (hyphen is not allowed in the name)

Lowercase names with underscores are a common convention for script variables, while readonly constants are often written in UPPER_SNAKE_CASE.


Expand Variables with $var and ${var}

Prefix the name with $ to expand its value. $name and ${name} usually do the same thing when the name stands alone.

bash
host=web01
printf 'host is %s\n' "$host"
output
host is web01

Use ${name} when the name sits next to other characters. Without braces, Bash reads the longest valid variable name it can:

bash
host=web01
printf 'without braces: %s\n' "$host_backup"
printf 'with braces: %s\n' "${host}_backup"
output
without braces: 
with braces: web01_backup

The first line looks empty because Bash searched for a variable called host_backup, not host followed by the literal _backup.


Quote Variable Expansions

Always quote expansions when the value may contain spaces, globs, or an empty string. Double quotes allow parameter expansion and command substitution inside; single quotes do not.

bash
path='/tmp/*.txt'
printf 'path literal: %s\n' "$path"
output
path literal: /tmp/*.txt

The * stayed literal because assignment does not expand globs. If you later use an unquoted $path, Bash may split words or expand the glob when the pattern matches files.

For deeper quoting rules — when to use ', ", and $'…' — see Bash concatenate strings.


Empty vs Unset Variables

An unset variable has no value at all. An empty variable exists but holds "". Those are different states for defaults and strict checks.

Inspect an unset name with declare -p:

bash
unset maybe
declare -p maybe
output
bash: declare: maybe: not found

Assign an empty string and check again:

bash
maybe=""
declare -p maybe
output
declare -- maybe=""

Test whether a name is set at all with ${name+x} inside Bash [ ] vs [[ ]] vs (( )):

bash
unset x
[[ -z ${x+x} ]] && echo 'x is unset'
x=""
[[ -z ${x+x} ]] && echo 'x is unset' || echo 'x is set (may be empty)'
[[ -z "$x" ]] && echo 'x is empty string'
output
x is unset
x is set (may be empty)
x is empty string

${x+x} expands to nothing when x is unset, so -z ${x+x} is true. After x="", the name is set but -z "$x" reports an empty string.


Change and Unset Variables

Reassign with another name=value line. Remove a name entirely with unset:

bash
retention_days=30
retention_days=7
printf 'retention_days=%s\n' "$retention_days"
unset retention_days
declare -p retention_days
output
retention_days=7
bash: declare: retention_days: not found

unset deletes the parameter. Assigning "" keeps the name but clears the value — useful when a script must know the variable was intentionally emptied.

Append to an existing string with +=:

bash
server="web"
server+="-01"
printf '%s\n' "$server"
output
web-01

Readonly Variables

Mark constants with readonly so later assignment fails:

bash
readonly config_file=/etc/app/config.yaml
config_file=/tmp/other.yaml
output
bash: config_file: readonly variable

Use readonly for values that should not change after they are set, such as a configuration path or script-wide constant.

A readonly variable cannot be reassigned or unset for the lifetime of that shell process. declare -r provides the same readonly attribute and can be combined with other declare options.


declare and Variable Attributes

declare (or typeset) creates variables and attaches attributes. Common variable-level options:

Option Meaning
-i Integer attribute — assignments are evaluated arithmetically
-r Read-only — same protection as readonly
-l Convert assigned uppercase characters to lowercase
-u Convert assigned lowercase characters to uppercase
-p Display attributes and value (declare -p name)

Arrays (-a, -A) and namerefs (-n) are separate topics — see split string into array for the first array pattern most scripts need.

For example, declare -i makes assignments arithmetic:

bash
declare -i count=10
count=count+5
printf 'count=%s\n' "$count"
output
count=15

Because count has the integer attribute, Bash evaluates count+5 as an arithmetic expression. For $(( )) loops and counters without declare -i, see Bash arithmetic.

Use declare -p name to display the variable's value and attributes:

bash
name="Ada Lovelace"
declare -p name
output
declare -- name="Ada Lovelace"

The -r flag appears in the output when a name is readonly:

bash
declare -r RO_TEST=1
declare -p RO_TEST
output
declare -r RO_TEST="1"

Shell Variables, Environment Variables, and Local Variables

A normal assignment creates a shell variable in the current Bash process. Child processes do not see it until you export it — Bash environment variables covers export, inheritance, and the difference from shell-only names.

Local variables inside functions use local. For now, remember:

  • name=value — current shell only
  • export name — also visible to child processes (see the environment-variables guide above)
  • local name — creates a variable local to the current function call; Bash uses dynamic scoping for functions — see Bash functions

Common Variable Errors

Symptom Likely cause Fix
command not found on assignment Spaces around = Use name=value with no spaces
Empty expansion when a suffix follows Missing braces Use ${host}_backup, not $host_backup
Word splitting or glob surprises Unquoted $var Quote: "$var"
readonly variable Reassigning a constant Do not reassign the variable. If you need it writable, remove the readonly or declare -r line and start a new shell or rerun the script
declare: name: not found Variable is unset Assign a value or test with ${name+x} before use

Practical Mini-Script

Scripts often read settings from the environment and fall back to defaults. Bash parameter expansion provides two useful forms for defaults:

  • ${VAR:-default} — use the default for this expansion only; the variable stays unset or empty
  • ${VAR:=default} — use the default and assign it when the variable is unset or empty

With :-, Bash uses the default value without assigning it:

bash
unset LOG_DIR
printf '%s\n' "${LOG_DIR:-/var/log/myapp}"
declare -p LOG_DIR 2>&1
output
/var/log/myapp
bash: declare: LOG_DIR: not found

The default printed, but LOG_DIR is still unset. The : "${VAR:=default}" idiom assigns only when the variable is unset or empty:

Save this as app_defaults.sh with a Bash shebang so direct execution picks Bash:

text
#!/bin/bash
: "${LOG_DIR:=/var/log/myapp}"
: "${RETENTION_DAYS:=7}"
printf 'LOG_DIR=%s RETENTION_DAYS=%s\n' "$LOG_DIR" "$RETENTION_DAYS"

Make it executable — Linux file permissions explains the mode bits chmod +x sets — and run it with built-in defaults:

bash
chmod +x app_defaults.sh && ./app_defaults.sh
output
LOG_DIR=/var/log/myapp RETENTION_DAYS=7

LOG_DIR=/tmp/logs ./app_defaults.sh passes LOG_DIR to that command only. It does not permanently export LOG_DIR in the calling shell:

bash
LOG_DIR=/tmp/logs ./app_defaults.sh
output
LOG_DIR=/tmp/logs RETENTION_DAYS=7

This example only uses the default-value forms; trimming, replacement, and substring operators use the same ${var} brace syntax covered in Bash compare strings.


Summary

Bash variables are parameters you create with name=value, expand with $name or ${name}, and remove with unset. Spaces around = break assignment, and ${name} is required when letters or digits follow the name.

An unset variable and an empty variable are different, and readonly adds a separate restriction that prevents later changes. Quote expansions when values may be empty or contain spaces, use readonly or declare -r for constants, and run declare -p when you need to see what Bash actually stored.

Environment variables, function-local variables, arrays, and advanced parameter expansion build on the same assignment and expansion rules covered here.


References


Frequently Asked Questions

Do Bash variables have data types?

Bash variables do not have fixed data types like variables in many programming languages. Values are normally treated as text, while attributes such as declare -i change how Bash handles assigned values and arithmetic.

Why does VAR = value fail?

Bash parses VAR = value as a command named VAR with arguments = and value. Assignment requires VAR=value with no spaces around =.

What is the difference between unset and empty?

An unset variable has no parameter entry. An empty variable exists and holds "". declare -p reports not found for unset names and declare -- name="" for empty ones. Tests such as ${name+x} distinguish the two.

When do I need ${var}?

Use ${var} when characters after the name could be read as part of the variable name (${host}_backup) or when you use parameter-expansion operators (${var:-default}). For a standalone name in double quotes, $var is enough.

Finished reading?Beta Get the key takeaways in seconds, then ask follow-up questions
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with 15+ years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)