Bash variables are wonderfully simple.
You can create one just by giving it a name:
name="Pavel"
count=5
message=
There is no need to declare a variable's type first. Bash doesn't require you to tell it whether a variable will contain text or a number.
But sometimes you want more control.
You may want a variable to be read-only, an integer, an array, exported to child processes, or automatically converted to uppercase or lowercase.
That's where Bash's declare built-in comes in.
What Is declare?
declare creates variables and controls their attributes.
Its basic syntax is:
declare [options] [name[=value] ...]
For example:
declare name="Pavel"
is essentially another way of writing:
name="Pavel"
For ordinary variables, the shorter form is usually preferable. The real value of declare comes from its options.
Think of declare as a way of telling Bash:
"Here is a variable, and this is how I want you to treat it."
Integer Variables: declare -i
The -i option gives a variable the integer attribute.
declare -i count=10
count=count+5
echo "$count"
Output:
15
Bash performs arithmetic when assigning to an integer variable.
You can, of course, also use Bash's more explicit arithmetic syntax:
count=$((count + 5))
declare -i is useful when you want the variable itself to carry the information that it represents an integer.
Indexed Arrays: declare -a
Bash supports indexed arrays, where elements are accessed using numeric indexes.
declare -a fruits
fruits[0]="apple"
fruits[1]="banana"
fruits[2]="orange"
You can then access an individual element:
echo "${fruits[1]}"
which prints:
banana
You can also initialize the array directly:
fruits=("apple" "banana" "orange")
The -a option is therefore useful when you explicitly want to declare an indexed array.
Associative Arrays: declare -A
Associative arrays use string keys instead of numeric indexes.
declare -A server
server[name]="web01"
server[ip]="192.168.1.20"
server[role]="frontend"
Now:
echo "${server[name]}"
prints:
web01
This is similar to a dictionary or map in many other programming languages.
The distinction is important:
declare -a array # indexed array
declare -A array # associative array
Read-Only Variables: declare -r
The -r option makes a variable read-only.
declare -r VERSION="1.0"
Trying to change it later:
VERSION="2.0"
produces an error similar to:
bash: VERSION: readonly variable
This can be useful for configuration values that should not change while a script is running.
Exported Variables: declare -x
The -x option gives a variable the export attribute.
declare -x APP_ENV="production"
This is equivalent in purpose to:
export APP_ENV="production"
A child process can then access the variable:
bash -c 'echo "$APP_ENV"'
For ordinary exporting, export is usually clearer. declare -x becomes useful when you're working with several variable attributes together.
Automatic Lowercase and Uppercase
Bash can automatically change the case of assigned values.
With -l:
declare -l environment
environment="PRODUCTION"
echo "$environment"
The result is:
production
With -u:
declare -u country
country="israel"
echo "$country"
The result is:
ISRAEL
This can be handy when normalizing user input before processing it.
Global Variables with declare -g
-g is particularly useful inside functions.
Normally, declare inside a function creates a local variable:
create_value() {
declare value="hello"
}
create_value
echo "$value"
The variable isn't available outside the function.
If you deliberately want to create or modify a global variable, use -g:
create_value() {
declare -g value="hello"
}
create_value
echo "$value"
Now the output is:
hello
Use this carefully. Global variables can make large scripts harder to understand, so a function should generally modify global state only when that is intentional and clear.
Inspecting Variables with declare -p
One of the most useful features of declare is that it can show you exactly how Bash sees a variable.
name="Pavel"
declare -p name
You might see:
declare -- name="Pavel"
For an integer:
declare -i count=10
declare -p count
you might see:
declare -i count="10"
And for an array:
declare -a fruits=("apple" "banana")
declare -p fruits
you'll see its array attribute and contents.
This makes declare -p particularly useful when debugging scripts.
Instead of simply asking:
echo "$variable"
you can ask Bash:
declare -p variable
and find out whether the variable is an integer, array, exported variable, read-only variable, and so on.
declare and Functions
declare can also inspect functions.
For example:
hello() {
echo "Hello!"
}
You can display the function definition with:
declare -f hello
Or list function names with:
declare -F
This is less common in everyday scripts, but useful when debugging a shell environment containing many functions.
The -t Attribute
The -t option gives a variable or function the Bash trace attribute.
declare -t variable
This is an advanced feature related to Bash's DEBUG and RETURN traps and isn't something most scripts need.
It's worth knowing that it exists, but you probably won't be reaching for `-t while writing your first Bash script—or your fiftieth.
Useful declare Options
Here are the options you're most likely to encounter:
| Option | Meaning |
|---|---|
-a | Indexed array |
-A | Associative array |
-f | Display function definitions |
-F | Display function names |
-g | Use global scope inside a function |
-i | Integer attribute |
-l | Convert assigned values to lowercase |
-p | Display variable declarations |
-r | Read-only variable |
-t | Trace attribute |
-u | Convert assigned values to uppercase |
-x | Export variable |
Several attributes can be combined when appropriate. For example:
declare -ir MAX_RETRIES=5
creates an integer, read-only variable.
declare vs. Normal Assignment
You don't need declare for every variable.
For a normal variable:
name="Pavel"
is simpler than:
declare name="Pavel"
Use declare when you actually need one of its features:
declare -i count
declare -r VERSION="1.0"
declare -a packages
declare -A server
declare -l environment
declare -x APP_ENV="production"
This keeps your scripts readable while still allowing Bash to enforce or provide useful variable behavior.
Getting Help
Because declare is a Bash built-in, use Bash's built-in documentation:
help declare
You can also verify that it is a built-in:
type declare
which reports:
declare is a shell builtin
For the complete documentation, consult:
man bash
and search for declare.
Conclusion
declare isn't required for ordinary Bash variables. Most of the time, this is all you need:
name="Pavel"
But when a variable needs additional behavior, declare becomes very useful.
You can use it to create:
declare -i count
declare -a packages
declare -A server
or give variables special attributes:
declare -r VERSION="1.0"
declare -l environment
declare -u country
declare -x APP_ENV="production"
And when you're unsure what Bash thinks a variable actually is:
declare -p variable
is often the quickest answer.
So don't think of declare simply as Bash's version of a traditional variable declaration. Think of it as a way to describe how Bash should treat a variable.
Once you start using arrays, functions, configuration variables, and more advanced Bash scripts, that distinction becomes quite useful.