Call variable based on content of another variable possible in BASH? - bash

Let's say, I have 3 variables, A=1, B=2, C=3 and finally a last variable containing the name of either of them (VAR=A). Is it possible to call A, B, C based on VAR's content without 'if's?
Like echo "${$VAR}"?

Yes.
eval echo \$$VAR
There is also a bash-only way of doing this, using indirect reference:
echo ${!VAR}

A=1
B=2
C=3
VAR=B
echo ${!VAR}
Output:
2
Documentation (man bash):
If the first character of parameter is an exclamation point (!), a level of variable indirection is introduced. Bash uses the value of the variable formed
from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the
value of parameter itself. This is known as indirect expansion. The exceptions to this are the expansions of ${!prefix*} and ${!name[#]} described below.
The exclamation point must immediately follow the left brace in order to introduce indirection.

Related

Why can substring variable expansion reference a variable without a dollar sign?

In bash, to get the first 4 characters of a variable, you can do:
variable='this is a variable'
echo ${variable:0:4}
Instead of hard-coding the length, you can reference a variable like this:
length=4
echo ${variable:0:$length}
However, it seems that you can leave off the $ off length as well:
echo ${variable:0:length}
It does not make sense to me that you should be able to do this because I always thought that to use/evaluate a variable, you have to prefix it with $.
In other languages, I would expect the text after each : to be a number or an expression that evaluates to a number. And in bash, length wouldn't evaluate to anything, but $length would.
This is confusing. Could someone help me understand what is going on here?
In general is correct to use the "$" symbol to expand a variable, but in some cases the bash auto-expands variable. For example in context like arithmetics or indirect expansion
(see Shell expansion to more detailed information).
However your case is a simple arithmetic context expansion.

Call variable from within variable

I have a source file which contains several libraries for names of variables. For example:
qvs_var1="ABC1"
qvs_var2="LMN2"
qvs_var3="LNE5"
qvs_var4="RST2"
....
Loading in the source file at the beginning of another file with:
source lib_file.csh
I now have access to the variables listed above. I want to access them dynamically and sequentially from a file prompting the variables to process. For example:
# Load in source file
source lib_file.csh
# Read in variables to process
vars=$(<variables_to_process.txt)
# For this example, vars = var1 var3
# Begin looping
For var in ${vars}
do
echo ${qvs_${var}}
done
Where the output should be: ABC1, and then LNE5. The error in the echo line above prompts: 'bad substitution'. What is the proper format to achieve what is needed?
What you are after is called indirection:
${parameter} The value of parameter is substituted. The braces are required when parameter is a positional parameter with more than one digit, or when parameter is followed by a character which is not to be interpreted as a part of its name.
If the first character of parameter is an exclamation point (!), a level of variable indirection is introduced. Bash uses the value of the variable formed from the rest of the parameter as the name of
the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion. The exceptions to this are the expansions of ${!prefix*} and ${!name[#]} described below. The exclamation point must immediately follow the left brace in order to introduce indirection.
source: man bash
Below you find a simple example:
$ foo_1="car"
$ bar="1"
We are now interested in printing the value of foo_1 using bar:
$ tmpvar="foo_$bar"
$ echo ${!tmpvar}
car

What does ! (exclamatory) mark inside curly braces ({}) when using variable in unix [duplicate]

This question already has answers here:
What is indirect expansion? What does ${!var*} mean?
(6 answers)
Closed 5 years ago.
Let var be a variable and it assigned a value /home/user as below
var=/home/user
when using this variable, i have seen it using both of the below format,
1) cd ${var}
2) cd ${!var}
what is the difference? for me second option is not working , if i echo second option returns empty.
In this case, it's indirect expansion(a), the var variable is expanded to create another variable name and then that is expanded again to get your eventual result:
pax$ abc=def
pax$ def=ghi
pax$ echo ${abc} # abc -> def, one level.
def
pax$ echo ${!abc} # abc -> def -> ghi, two levels.
ghi
From the bash man page:
If the first character of parameter is an exclamation point (!), it introduces a level of variable indirection. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion.
(a) It can have other more complex effects in other situations, such as when you use ${!prefix*} or ${!name[#]} but your case is the simpler one.

Bash indirect references: ${!t} notation and eval

I just came along the short notation of bash's indirect references ${!t}. I'm used to precede indirect references of the kind \$$t by eval. However, using the ${!t} notation it seems that I do not need to do this:
# d=e e=f; eval y=${!d}; echo $y
f
# d=e e=f; y=${!d}; echo $y
f
Why do we need no eval here? Is it implicitly called?
From section 3.5.3 Shell Parameter Expansion of the Bash Reference Manual:
If the first character of parameter is an exclamation point (!), it introduces a level of variable indirection. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion. The exceptions to this are the expansions of ${!prefix*} and ${!name[#]} described below. The exclamation point must immediately follow the left brace in order to introduce indirection.
The eval \$$t version of indirection is manually causing two evaluations of the line contents. The first to get the indirect variable name and the second to get its value.

variable of Variable

I have to print a variable value which is art variable.
eg. variables are
A = X
Z_X = Test
Set in shell using
setenv A X
setenv Z_X Test
I want to print $Z_X value using $A
I am trying but without any success.
echo ${Z_${A}}
echo ${Z_[$A]}
could anyone tell me where I am wrong.
regards
A = X
Z_X = Test
This seems wrong; in csh, you need to use the set keyword to assign variables; in addition, the convention is also to use lower case for "normal" variables, and UPPER CASE for environment variables:
set a = x
set z_x = Test
You can then use eval to get what you want:
% eval echo \$z_$a
Test
% set x = `eval echo \$z_$a`
% echo $s
Test
This may be dangerous if you don't trust the source of $a, since it may also do a rm -rf / or something similarly dangerous (but if you trust the source of $a, it's perfectly fine).
You can get a list of all variables with set:
% set | grep ^z_$a
z_x Test
% set | grep ^z_$a | awk '{print $1}'
z_x
Which is the only safe way I can figure out to do what you want.
Generally this is a bad idea, and you should rather rethink your approach.
You can use indirect expansion:
name=Z_$A
echo ${!name}
From the manual:
If the first character of parameter is an exclamation point (!), a level of variable indirection is introduced. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion. The exceptions to this are the expansions of ${!prefix*} and
${!name[#]} described below. The exclamation point must immediately follow the left brace
in order to introduce indirection.
Or indirect references:
name=Z_$A
eval echo \$$name
You can find more about indirect references in the guide.

Resources