Bash — The declare Built-in

Learn how Bash’s declare built-in lets you control variable attributes, create arrays, define read-only or integer variables, export values, and inspect how Bash treats your variables.

Bash — The declare Built-in

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:

OptionMeaning
-aIndexed array
-AAssociative array
-fDisplay function definitions
-FDisplay function names
-gUse global scope inside a function
-iInteger attribute
-lConvert assigned values to lowercase
-pDisplay variable declarations
-rRead-only variable
-tTrace attribute
-uConvert assigned values to uppercase
-xExport 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.

Read next

Bash — The fg Built-in

Learn how Bash’s fg built-in brings background and suspended jobs back to the foreground. Discover how to use fg, bg, and jobs, understand job numbers, and manage running commands without restarting them.

Bash — The bg Built-in

Learn how Bash’s bg built-in lets you resume stopped jobs in the background without interrupting your terminal session. Discover how to use Ctrl+Z, bg, and jobs, understand job specifications, and learn when to use bg instead of fg or &.

Bash — The dirs Built-in

A concise excerpt for the `dirs` post: > Learn how Bash’s `dirs` built-in lets you inspect and manage the directory stack. Explore `-p`, `-l`, `-v`, and `-c`, select specific entries, combine options, and see how `dirs` works together with `pushd` and `popd`.