Calling a variable of variable from a file

Hi All,

I have file which have looks like below

abc=${def}
def=${efg}
efg= "this is the actual value"

based on "abc" value I have to call "efg" value , Am using below lines but it is not working

#!/bin/bash
source file.txt
echo $abc

The sequence of the file you source in is important. When abc is set, the value of def is still Null.

When def is set, the value of efg is still Null too.

Trying to set variable efg like this will likely cause an error anyway because of the space.

I assume you would need to do this:-

efg="this is the actual value"
def=${efg}
abc=${def}

You can then run the script and should get your output.

I hope that this helps,
Robin

1 Like

Indeed, it IS working. Exactly as expected from the specifications of the bash shell. It may not do what you intend to do, though. Please explain more explicitly what your intentions are.

Did you consider "indirect expansion" ( ${!var} ) that recent bash versions offer, or "associative arrays"?

In this case I'd say the same as i thought when i read the first post: there must have happened a serious flaw in the design process before to make such outrageous means necessary. This is the same as the old:

eval \$${var}

which should equally be avoided like the plague. Life is too short to waste it chasing eval s once they go haywire (which the always do sooner or later).

I hope this helps.

bakunin

No, does not help, sorry.

echo "${!var}"

is nicer than

eval echo \"\$$var\"

especially if more context is added.
Sourcing shell code means you must trust the external source.
Sourcing variables is only a little safer, you must still trust it.

Back to the original problem, here is an elegant method

abc=def
def=efg
efg="this is the actual value"

varvar(){
newres=$1
while [ -n "$newres" ]
do
  res=$newres
  newres=${!res}
done
echo "$res"
}

varvar abc
varvar def
varvar efg

I beg to respectfully differ: both are great methods to shoot oneself into foot, even if i have to concede that your method is doing so with a nicer looking gun.

Perhaps the only reason to use such an indirect evaluation (regardless of using your construct or mine) is because the function doesn't know (at writing time) the variables true name. This establishes a sort-of passing by reference (instead of the usual passing by value).

To give an example for what i mean, if you have this code:

x=value
func "$x"

then inside the function you "know" the name of your received variable - $1:

func()
{
parm1="$1"

do_something "$parm1"
....
}

Whereas here:

x="value"
func x    # notice: variable name instead of value

func()
{
parm1=${!1}       # your way
eval parm1=\$$1  # my way

...
}

You have not the same kind of knowledge because you cannot expand $1 but have to expand what $1 expands to.

In languages such as C you pass around pointers to data (or, in FORTRAN, you pass by reference) because you want to manipulate the data statically across functions: one function creates a list and passes a pointer to it (instead of the copied structure) to another function which adds a new element. Both functions work on the same data instead of one calling the other with a copy of the original (which would be lost when the function returns).

But in scripting languages there is no such thing like pass by reference and there is no such thing as common, static data you can manipulate. You can try to dot-execute all your functions to get there, but this would most probably lead to desaster quite fastly. So there is no real application for this kind of "indirect evaluation" other than perhaps supporting bad design. I am sure that - by reformulating the problem - it would perhaps be possible to come up with a simpler and cleaner solution which will not rely on double dereferencing to get to a variables content.

And there is one more problem: if you look closely at the second variation with the double dereference you will notice that it relies on the existence of a variable named "x" which is defined outside, in the calling function. This is a violation against the rule of encapsulation: you should use at one level only what you defined on that level, not something from the background environment, because once this environment changes you are in deep kimchi.

bakunin