Shell builtins · bash builtin
declare
Create variables with attributes (array, associative array, integer, read-only, exported), or show how variables are defined.
declare [-aAfFgiIlnrtux] [-p] [NAME[=VALUE] ...]
Plain assignment (x=1) creates an ordinary string variable. declare creates a variable
with attributes: -a indexed array, -A associative array (the only way to get one),
-i integer, -r read-only, -x exported, -l/-u forced lower or upper case, and -n
a name reference to another variable. typeset is an older synonym kept for ksh
compatibility.
Inside a function, declare makes the variable local to that function, exactly like
local. Add -g to create or modify a global from within a function instead.
declare -p NAME is the best way to inspect a variable: it prints a command that would
recreate it, with its attributes and exact quoting, so empty strings, arrays and odd
characters are all visible. declare -f prints function definitions and declare -F only
their names.
Examples
Inspect a variable exactly with -p
name="Alice Moreau"
empty=""
list=(one "two words" three)
declare -p name empty list
declare -- name="Alice Moreau" declare -- empty="" declare -a list=([0]="one" [1]="two words" [2]="three")
-p shows each variable as a declare command, with attributes (-a for the array) and
quoting. It makes the difference between an empty string and a value with spaces
obvious, which echo hides.
Create an associative array with -A
declare -A port=([web]=80 [db]=5432)
port[cache]=6379
for k in "${!port[@]}"; do echo "$k -> ${port[$k]}"; done | sort
cache -> 6379 db -> 5432 web -> 80
Associative arrays use strings as keys and must be declared with -A first. ${!port[@]}
lists the keys. Their order is not defined, hence the sort.
Forgetting -A gives an indexed array instead
colors[red]=ff0000
colors[green]=00ff00
declare -p colors
declare -a colors=([0]="00ff00")
Without declare -A, colors is an indexed array and red and green are evaluated
as arithmetic, where an unknown name is 0. Both assignments go to index 0, and the second
overwrites the first.
Make a variable evaluate arithmetic with -i
declare -i total=10
total+=5
total=total*2
echo "$total"
total="hello"
echo "after assigning text: $total"
30 after assigning text: 0
With -i, every assignment is evaluated as arithmetic, so += adds rather than
appending and total*2 multiplies. A string that is not a number evaluates to 0, without
an error. Many people prefer explicit $(( )) for that reason.
Make a constant with -r
declare -r MAX_RETRIES=3
MAX_RETRIES=5
echo "still $MAX_RETRIES"
/bin/bash: line 2: MAX_RETRIES: readonly variable still 3
Assigning to a read-only variable is an error (status 1, the script continues unless set
-e is on). readonly NAME=value is the POSIX spelling of the same thing.
Force lower or upper case with -l and -u
declare -l answer
declare -u code
answer="YeS"; code="eu-west-1"
echo "$answer $code"
yes EU-WEST-1
The case conversion is applied on every assignment, which makes comparisons such as
[[ $answer == yes ]] robust against how the user typed it.
Refer to another variable by name with -n
add_item() {
declare -n list=$1
list+=("$2")
}
fruits=(apple)
add_item fruits banana
add_item fruits cherry
declare -p fruits
declare -a fruits=([0]="apple" [1]="banana" [2]="cherry")
list becomes an alias for the variable whose name is in $1, so the function modifies
the caller's array. Namerefs (bash 4.3+) replace most uses of eval for this.
declare inside a function makes a local variable
count=1
f() { declare count=99; echo "inside: $count"; }
g() { declare -g count=42; }
f; echo "after f: $count"
g; echo "after g: $count"
inside: 99 after f: 1 after g: 42
In a function, declare behaves like local, so f leaves the global alone. -g
forces a global, which is how g changes it.
List function names or definitions
source src/util.sh
declare -F
declare -f log
declare -f die
declare -f log
log ()
{
printf '%s %s\n' "$(date +%H:%M:%S)" "$*" 1>&2
} -F prints only the names of defined functions; -f NAME prints the full definition, as
bash has reformatted it.
Export with -x and remove attributes with +
declare -x REGION=eu
bash -c 'echo "child: $REGION"'
declare +x REGION
bash -c 'echo "child: [$REGION]"'
child: eu child: []
-x is the same as export. A plus sign removes an attribute, so +x stops exporting
while keeping the value in the shell.
Common pitfalls
Assigning to
arr[key]withoutdeclare -Asilently creates an indexed array, collapsing every non-numeric key into index 0.declareinside a function is local. A function meant to set up globals needsdeclare -g.declare -iturns any non-numeric string into 0 without an error, hiding bad input.declare x=$(cmd)returnsdeclare's status, notcmd's, soset -emisses a failure. Declare and assign on separate lines.
GNU vs BSD and macOS
The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).
declareis bash-only (zsh and ksh havetypesetwith similar but not identical options). Associative arrays need bash 4 or newer; macOS still ships bash 3.2 as/bin/bash, wheredeclare -Afails. Install a newer bash or use zsh.
Options worth knowing
A selection, described in our own words. For the full list, see bash(1), SHELL BUILTIN COMMANDS.
| Option | What it does |
|---|---|
-a | Make the names indexed arrays. |
-A | Make the names associative arrays (string keys). |
-i | Give the integer attribute: assignments are evaluated as arithmetic. |
-r | Make the names read-only. |
-x | Export the names to child processes. |
-l | Convert values to lower case on assignment. |
-u | Convert values to upper case on assignment. |
-n | Make the name a reference to the variable named by its value. |
-g | Inside a function, create or modify a global variable. |
-p | Print the attributes and value of each name as a reusable declare command. |
-f | Act on functions; with no other attribute, print their definitions. |
-F | Print function names (and attributes) without their bodies. |
-t | Give the trace attribute, so functions inherit DEBUG and RETURN traps. |
-I | Make a new local variable inherit the value and attributes of the same name in an outer scope. |
Related
localDeclare variables inside a function that disappear when it returns, leaving any global of the same name untouched.exportMark shell variables (or bash functions) to be passed to every program the shell starts.unsetRemove shell variables, array elements or functions, so they no longer exist rather than being empty.mapfileRead lines from standard input into an indexed array, one line per element (also called readarray).setTurn shell options such as -e, -u, -x and pipefail on or off, and replace the positional parameters.- VariablesAssigning and reading shell variables, the no-spaces rule, braces, unset vs empty, scope, readonly, and the special variables bash sets for you.
- ArraysIndexed arrays in bash, creating, reading, appending, looping, slicing and removing elements, and using them to build command lines safely.
- Associative arraysBash's string-keyed maps, declare -A, testing whether a key exists, counting things, loading a config file, and the unordered-keys and missing-declare traps.
- FunctionsDefining and calling bash functions, arguments, local variables, return status versus output, namerefs, and sourcing a function library.