Bash local AND readonly variable
The bash man page summarizes things thusly for the declare
command:
-r Make names readonly. These names cannot then be assigned values
by subsequent assignment statements or unset.
and
When used in a function, declare and typeset make each name local, as with
the local command, unless the -g option is supplied.
So if you declare
within a function, the variable you declare will be local by default. And if you use the -r
option, it will be read-only.
$ cat testv
#!/usr/bin/env bash
test1() {
declare -r var="$1"
var="bacon"
}
s=foo
test1 bar
echo "$s - $var"
$ bash testv
testv: line 5: var: readonly variable
foo -
First attempt: local readonly var1
That is the way I used to define it. It is wrong. I will define my variable var1
as local
, but it will not be readonly
, as you can see on example below, I can change the value of var1
, and I don't want that!
:~$ (
> myfunction()
> {
> # Define variable
> local readonly var1="val1"
>
> echo "Readonly output:"
> readonly | grep -E 'readonly|local|var1'
> echo ""
>
> echo "Local output:"
> local | grep -E 'readonly|local|var1'
> echo ""
>
> var1="val2"
> echo "VAR1 INSIDE: ${var1}"
> }
> myfunction
> echo "VAR1 OUTSIDE: ${var1}"
> )
Readonly output:
Local output:
var1=val1
VAR1 INSIDE: val2
VAR1 OUTSIDE:
Second attempt: readonly local var1
This time it will define var1
as readonly
, but it will also define a variable called local
, so using this way it will not handle local
as keyword, it will be a variable name.
Check also that the scope of var1
is not local
, in fact it is global
, we can see the value of var1
outside the function.
:~$ (
> myfunction()
> {
> # Define variable
> readonly local var1="val1"
>
> echo "Readonly output:"
> readonly | grep -E 'readonly|local|var1'
> echo ""
>
> echo "Local output:"
> local | grep -E 'readonly|local|var1'
> echo ""
>
> echo "VAR1 INSIDE: ${var1}"
> }
> myfunction
> echo "VAR1 OUTSIDE: ${var1}"
> )
Readonly output:
declare -r local
declare -r var1="val1"
Local output:
VAR1 INSIDE: val1
VAR1 OUTSIDE: val1
As it should be: local -r var1
This way it will do exactly what I want, it will define var1
as scope local
AND readonly
.
:~$ (
> myfunction()
> {
> # Define variable
> local -r var1="val1"
>
> echo "Readonly output:"
> readonly | grep -E 'readonly|local|var1'
> echo ""
>
> echo "Local output:"
> local | grep -E 'readonly|local|var1'
> echo ""
>
> #var1="val2"
> echo "VAR1 INSIDE: ${var1}"
> }
> myfunction
> echo "VAR1 OUTSIDE: ${var1}"
> )
Readonly output:
declare -r var1="val1"
Local output:
var1=val1
VAR1 INSIDE: val1
VAR1 OUTSIDE:
We can define it as below also, but one line is better than two!
local var1="val1"
readonly var1