what is difference in `declare -r` and `readonly` in bash?

tl;dr readonly uses the default scope of global even inside functions. declare uses scope local when in a function (unless declare -g).

At first glance, no difference.

Examining using declare -p

$ declare -r a=a1
$ readonly b=b1
$ declare -p a b
declare -r a="a1"
declare -r b="b1"

# variable a and variable b are the same

Now review the difference when defined within a function

# define variables inside function A
$ function A() {
      declare -r x=x1
      readonly y=y1
      declare -p x y
  }

$ A
declare -r x="x1"
declare -r y="y1"

# ***calling function A again will incur an error because variable y
#    was defined using readonly so y is in the global scope***

$ A
-bash: y: readonly variable
declare -r x="x1"
declare -r y="y1"

# after call of function A, the variable y is still defined

$ declare -p x y
bash: declare: x: not found
declare -r y="y1"

To add more nuance, readonly may be used to change a locally declared variable property to readonly, not affecting scope.

$ function A() {
    declare a="a1"
    declare -p a
    readonly a
    declare -p a
}

$ A
declare -- a="a1"
declare -r a="a1"

$ declare -p a
-bash: declare: a: not found


Note: adding -g flag to the declare statement (e.g. declare -rg a="a1") makes the variable scope global. (thanks @chepner).

Note: readonly is a “Special Builtin“. If Bash is in POSIX mode then readonly (and not declare) has the effect “returning an error status will not cause the shell to exit“.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)