opscape

Shell builtins · bash builtin

unset

Remove shell variables, array elements or functions, so they no longer exist rather than being empty.

unset [-f | -v | -n] NAME...

8 of 8 examples run in Debian 13.7 on 2026-10-31 · manual: bash(1), SHELL BUILTIN COMMANDS

unset NAME deletes a variable: afterward it is not set at all, which is different from being set to an empty string. The distinction matters to ${var-default}, [[ -v var ]] and set -u, and an unset variable also disappears from the environment of child processes if it was exported.

The same builtin removes functions (unset -f name) and single array elements (unset 'arr[2]'). Removing an element leaves a gap in the indices rather than shifting the others down, which surprises people used to lists in other languages.

Without an option, bash tries a variable first and then a function of that name. In scripts, say which you mean with -v or -f. Read-only variables, such as those made with readonly or declare -r, cannot be unset.

Examples

Remove a variable

name="Alice"
unset name
echo "name=[$name]"
echo "${name-it is unset}"
output
name=[]
it is unset

After unset, expanding name gives an empty string. ${name-default} (no colon) uses the default only when the variable is unset, which shows it really is gone.

Empty is not the same as unset

a=""
unset b
[[ -v a ]] && echo "a is set (to an empty string)"
[[ -v b ]] || echo "b is not set"
echo "a: [${a-default}]  b: [${b-default}]"
output
a is set (to an empty string)
b is not set
a: []  b: [default]

-v tests whether a variable exists. ${var-default} substitutes only for unset variables, while ${var:-default} would also replace the empty string.

Remove a variable from the environment of child processes

export DEBUG=true
bash -c 'echo "child: DEBUG=[$DEBUG]"'
unset DEBUG
bash -c 'echo "child: DEBUG=[$DEBUG]"'
output
child: DEBUG=[true]
child: DEBUG=[]

Unsetting an exported variable removes it from the environment too. To hide it from one command only, use env -u DEBUG cmd.

Remove a function with -f

ls() { echo "fake ls"; }
ls scripts
unset -f ls
ls scripts
output
fake ls
backup.sh
greet.sh

Once the function is gone, ls resolves to the real program again.

Remove one array element

fruits=(apple banana cherry date)
unset 'fruits[1]'
echo "values:  ${fruits[*]}"
echo "indices: ${!fruits[*]}"
echo "count:   ${#fruits[@]}"
output
values:  apple cherry date
indices: 0 2 3
count:   3

banana is removed, but the other elements keep their indices, so there is now a gap at 1. Quote 'fruits[1]' so the brackets are not taken as a glob pattern matching a file named fruits1. Re-pack with fruits=("${fruits[@]}") if you need contiguous indices.

Remove a whole array

list=(a b c)
unset list
echo "elements left: ${#list[@]}"
output
elements left: 0

unset name without an index removes the entire array.

Read-only variables cannot be unset

readonly VERSION=2.4.1
unset VERSION
echo "status $?, VERSION=$VERSION"
output
/bin/bash: line 2: unset: VERSION: cannot unset: readonly variable
status 1, VERSION=2.4.1

bash refuses and returns 1. Read-only variables last until the shell exits.

Unset variables trip set -u

set -u
tmpdir=/tmp/work
unset tmpdir
echo "removing $tmpdir"
outputexit 127
/bin/bash: line 4: tmpdir: unbound variable

With set -u, expanding a variable after it has been unset is a fatal error, so the script stops instead of running a command with an empty path. bash 5.2 exits with 127 here.

Common pitfalls

  • unset arr[1] without quotes: if a file named arr1 exists, the glob expands to it and the wrong name is unset. Write unset 'arr[1]'.

  • Assuming unset on an array element shifts the rest down. Indices stay as they were; ${#arr[@]} drops, but the highest index does not.

  • unset with no option removes a variable of that name if one exists, and a function only if not. Use unset -f for functions to avoid deleting a variable by accident.

  • Setting a variable to empty (VAR=) when a program checks whether it is defined; some tools treat an empty HTTP_PROXY or GIT_DIR differently from an absent one. Use unset.

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).

  • unset, -f and -v are POSIX. Array elements and -n (namerefs) are bash features.

Options worth knowing

A selection, described in our own words. For the full list, see bash(1), SHELL BUILTIN COMMANDS.

OptionWhat it does
-vTreat each name as a variable.
-fTreat each name as a shell function.
-nIf the name is a nameref, unset the reference itself, not the variable it points to.

Related