vv=1
cc() { local vv=2; echo $vv; unset vv; echo "${vv}3"; }
cc
echo $vv
Gives:
2
3
1
I was expecting:
2
13
1
How can I access the global variable once a variable with the same name has been set local in a function?
I don't think you can. If it's an exported environment variable you can find it by reading the environment, but as far as a global variable masked by a local one, AFAIK you're out of luck. Check the contents of, and copy as necessary, before declaring your local variable.
Related
I'd like to use a global variable in a function but don't want the change to go outside the function. So I defined a local variable initialized to the value of the global variable. The global variable has a great name, so I want to use the same name on the local variable. This seems doable in Bash, but I'm not sure if this is undefined behavior.
#!/bin/bash
a=3
echo $a
foo() {
local a=$a ## defined or undefined?
a=4
echo $a
}
foo
echo $a
Gives output:
3
4
3
Expansion happen before assignment (early on) as the documentation states:
Expansion is performed on the command line after it has been split into words.
So the behavior should be predictable (and defined). In local a=$a when expanding $a it's still the global one. The command execution (assignment/declaration) happens later (when $a has already been replaced by its value).
However I am not sure this would not get confusing to have essentially two different variables (scope dependent) with the same name (i.e. appearing to be the one and same). So, I'd rather question wisdom of doing so on coding practices / readability / ease of navigation grounds.
There is a new shell option in Bash 5.0, localvar_inherit, to have local variables with the same name inherit the value of a variable with the same name in the preceding scope:
#!/usr/bin/env bash
shopt -s localvar_inherit
myfunc() {
local globalvar
echo "In call: $globalvar"
globalvar='local'
echo "In call, after setting: $globalvar"
}
globalvar='global'
echo "Before call: $globalvar"
myfunc
echo "After call: $globalvar"
with the following output:
Before call: global
In call: global
In call, after setting: local
After call: global
If you don't have Bash 5.0, you have to set the value in the function, as you did in your question, with the same result.
This question already has an answer here:
Accessing environment variables that don't map to valid shell variable names
(1 answer)
Closed 5 years ago.
We are using elastic beanstalk. Some values are environment properties of the environment. When I perform a container_command I'm able to read this properties as environment variables. The problem is the following: a lot of properties are named like this db:user or collector:server and after that the value.
How can I read this values? I can interpret them as environment variables. So the environment properties with 'normal' names I can read. But not those ones who contain a ':' in their name:
To test (+ make it clearer for people who don't know elastic beanstalk) I've created this. The global goal is to read the value of a variable which contains a ':' in its name.
#!/bin/bash
${myvar:test}="hey"
echo ${myvar:test}
$./test.sh
$./test.sh: line 3: =hey: command not found
: isn't an allowed character in shell variables at all, and ${test:foo} has a completely separate meaning (it expands $test with a default value of foo if no variable named test is defined).
If your operating system is Linux, however, you can directly parse your original environment variables from procfs:
#!/usr/bin/env bash
declare -A env=( ) ## <- note that this requires bash 4.0 or newer
while IFS= read -r -d '' envvar; do
[[ $envvar = *:* ]] || continue
varname=${envvar%%=*}
value=${envvar#*=}
env[$varname]=$value
done < /proc/self/environ
echo "The value of the environment variable db:user is: <<${env[db:user]}>>"
Note that to test this, though, you'll need to be able to actually create an environment variable with a literal colon, and your code currently fails at doing so. Consider instead:
env db:user="test value for db:user" ./yourscript
I want to make this variable
local to="$HOME/root_install/grunt"
be available to the entire file
makeGrunt(){
# set paths
local to="$HOME/root_install/grunt"
cd $to
sudo npm install -g grunt-init
sudo git clone https://github.com/gruntjs/grunt-init-gruntfile.git ~/.grunt-init/gruntfile
sudo grunt-init gruntfile
}
In POSIX-like shells - unless you use nonstandard constructs such as local, typeset, or declare - variables created implicitly through
assignment have global scope in the shell at hand.
Thus, to="$HOME/root_install/grunt" will make variable $to available anywhere in the current shell - unless you're inside a function and that variable was explicitly marked as local.
andlrc's helpful answer demonstrates the pitfalls associated with subshells - subshells are child processes that are clones of the original shell - they see the same state, but cannot modify the original shell's environment.
Bash shells use dynamic
scopes
which means that all variables are available for all called functions, commands,
etc. Consider this:
var=1
a() {
local var=2
b
}
b() {
echo "$var"
}
a # 2
b # 1
a # 2
When using the local keyword a variable will be available for the function, in
where it's defined, but also within all functions called from that function.
The same applies when a variable is created without the local keyword. With
that exception that it will also be available outside the function.
One more thing to be aware of is that whenever a subshell is created a variable
will not be able to "leave" it, i.e. when a pipe is involved. Consider this:
sum=0
seq 3 | while read -r num; do
sum=$((sum + num))
echo "$sum" # will print 1, 3 and 6
done
echo "$sum" # 0 huh? 1 + 2 + 3 = 0?
if suppose I have an local variable input <- 100 Can You suggest me How to use the local varaibles in RS.eval(c1,xx <-input) please comment
I'm trying to determine the existing HDDs in each system using a for loop as show below, the problem is when I try to set the variable using the below code i get sda=true: command not found. What is the proper way to do this?
#!/bin/bash
for i in a b c d e f
do
grep -q sd$i /proc/partitions
if [ $? == 0 ]
then
sd$i=true
else
sd$i=false
fi
done
You need to use an array or declare:
declare sd$i=true
I would use an array in this case. For example:
$ i=a
$ sd[$i]=true
$ echo ${sd[a]}
true
As another poster stated, if you want to do this without an array, you can instead make a local variable by using syntax like declare sd$i=true. If you want to make a global variable, use export sd$i=true.
BASH FAQ entry #6: "How can I use variable variables (indirect variables, pointers, references) or associative arrays?": "Assigning indirect/reference variables"