I like to organize my code with functions, as I am using function I like to use local
variables also. As much as possible I use read-only
variables, so if I make any mistake inside my code it will be easily noticed.
But I have been using it wrong for a long time. So I decided to write it to share my experience.
How to define local
AND read-only
inside bash function? (See the answer and explanation below).
To add more nuance, readonly may be used to change a locally declared variable property to readonly, not affecting scope. 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".
Read-only VariablesShell provides a way to mark variables as read-only by using the read-only command. After a variable is marked read-only, its value cannot be changed. /bin/sh: NAME: This variable is read only.
An alternative if gdb is unavailable: You can use the enable command to load a custom builtin that will let you unset the read-only attribute. The gist of the code that does it: SETVARATTR (find_variable ("TMOUT"), att_readonly, 1); Obviously, you'd replace TMOUT with the variable you care about.
You can't delete mySite. The whole point of the readonly command is to make it final and permanent (until the shell process terminates). If you need to change a variable, don't mark it readonly.
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
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 -
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With