LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   BASH - How to access a variablized variable? (https://www.linuxquestions.org/questions/linux-newbie-8/bash-how-to-access-a-variablized-variable-775078/)

DevonB 12-11-2009 09:34 PM

BASH - How to access a variablized variable?
 
Greetings everone, I'm new here and need a bit of help.

I'm having an issue trying to pull the value out of a variable I have set. I have a loop that its variable is part of the name of a different variable. I can set it, but I cannot grab its value. My problem is, I don't know how to force BASH to treat the entire block of text as a single variable; it keeps breaking it into two. How can I make it treat it as one? Example -

Code:


STRING1=MyName
SOME_VALUE=Devon

STRING2_$STRING1_REST_OF_STRING=SOME_VALUE < this sets properly.

My problem is, how do I access it? If I try this -

echo $STRING2_${STRING1}_REST_OF_STRING, it treats is as two variables. If I print it out, I get basically

${STRING1}_REST_OF_STRING

with the $STRING2_ missing. I know it's doing it because it's splitting my variable into $STRING2_ as one variable (which is set to nothing) and ${STRING1}_REST_OF_STRING as a separate variable, which also is set to nothing.

If I try -

${STRING2_${STRING1}_REST_OF_STRING}

I get an error about bad substitution.

I'm assuming since I can set the "big" variable, there is some built-in that I can use to force it to treat it as one variable and not two separate varaibles, but what is it? Google has left me empty handed so far. I've tried single quotes, double quotes, I've even got it to set to another variable properly, but then it treats that variable as a literal, and I cannot get it to print out its value. For example -

Code:

NEW_STRING=`\$STRING_2${STRING1}_REST_OF_STRING`
It will print out the literal "$STRING_2MyName_REST_OF_STRING", but I can't get to the value I set it to, which is Devon.

Help, please!

Devon

GrapefruiTgirl 12-11-2009 09:44 PM

Hopefully this will help you:

Code:

sasha@reactor:~$ STRING1=MyName
sasha@reactor:~$ SOME_VALUE=Devon
sasha@reactor:~$ newvar=$(eval echo \${STRING2_$STRING1_REST_OF_STRING=$SOME_VALUE})
sasha@reactor:~$ echo $newvar
Devon
sasha@reactor:~$
sasha@reactor:~$ eval echo \${STRING2_$STRING1_REST_OF_STRING}           
Devon
sasha@reactor:~$

Sasha

ghostdog74 12-11-2009 10:22 PM

please, try to use arrays/associative arrays, now that newer bash supports them.
Code:

declare -a array
declare -A dict
STRING1=MyName
SOME_VALUE=Devon
array[0]=$SOME_VALUE
dict["STRING2_$STRING1_REST_OF_STRING"]=$SOME_VALUE

#print array value
echo ${array[0]}

#print associative array
echo ${dict[@]}
echo ${array["STRING2_$STRING1_REST_OF_STRING"]}


konsolebox 12-11-2009 11:02 PM

If you already have or you can install bash 4.0, use associative arrays as ghostdog74 also suggested. It will really simplify things.

However if you still want to know how, perhaps you can play around with the ${!VAR} feature of bash.

Code:

VAR=data
VARPTR=VAR
echo ${!VARPTR}


ghostdog74 12-12-2009 12:30 AM

Quote:

Originally Posted by konsolebox (Post 3788520)
If you already have or you can install bash 4.0, use associative arrays as ghostdog74 also suggested. It will really simplify things.

However if you still want to know how, perhaps you can play around with the ${!VAR} feature of bash.

Code:

VAR=data
VARPTR=VAR
echo ${!VARPTR}


should be careful when using this. try this
Code:

$ VAR=data
$ VARPTR=VAR
$ VARPTR1=VARPTR
$ echo ${!VARPTR1}
VAR

what do you think ${!VARPTR1} should be?

konsolebox 12-14-2009 03:39 AM

hmmm.. my guess :-).. VAR also no? it's obvious why? .. to get data using VARPTR1.. we need to reparse it:
Code:

TEMP=${!VARPTR1}
echo "${!TEMP}"

or
Code:

eval echo \"\${!${!VARPTR1}}\"
-- edit --

and if i'm to use another variable pointer, i'll call it VARPTRPTR although in my projects i alwayse use *VAR like:
Code:

ARRAY=()
ARRAYVAR=ARRRAY
ARRAYVARVAR=ARRAYVAR

such things does not appear much in my codes though. i just gave an example.

ghostdog74 12-14-2009 03:40 AM

and VAR is "data" , right?

konsolebox 12-14-2009 03:48 AM

yup. ... i sort of don't get the point. they're just variables pointing to strings right? .. not really pointers.. only ${!PARAM} does the magic.

ghostdog74 12-14-2009 03:55 AM

Quote:

Originally Posted by konsolebox (Post 3790642)
hmmm.. my guess :-).. VAR also no? it's obvious why? .. to get data using VARPTR1.. we need to reparse it:

that's where the problem lies. At run time, you won't know how many levels you are going to parse. the syntax "${!<param>}" somehow is not used like that in the context of references.

konsolebox 12-14-2009 04:02 AM

Well it's enough if you're after only 1 level of reference. I don't really mean we should consider the method. I just gave the example for the single level.. It's up for the OP what he'll do .. either he still consider the re-reference thing or use eval.. but as I said before it's also better if he just use the hashes. You'll usually have to decide what other method to use when you're after at least more than 2 levels. I don't do that in my codes.

GrapefruiTgirl 12-14-2009 09:19 AM

OK, the OP hasn't been back since asking this question.. Rather than perpetuate the discussion of 'this way is better, that way is better', I think we should wait for the OP's return and see if he/she has any input about the methods above. We don't even know what OS or shell the OP is using.

Frankly though, I don't see what was so difficult or horrid about my first reply, nor why using arrays would be (any/much) better. And, much of the above ideas imply not only a Bash shell, but assume that the OP has a new Bash shell, or is willing to get one; we know where assuming can lead us ;)

@ Ghostdog, respectfully: your shell scripting help has many times proven very helpful to myself and others, and I appreciate that -- you're knowledgeable in this area, no question -- but on this subject of arrays, I'm getting a little bit of mixed messages from you. In this thread, you're suggesting use of arrays, yet in this other thread of mine you suggest I avoid (extensive use of) arrays and/or switch languages if I need a lot of array-like constructs :scratch: so why the difference? Was it the desire for POSIX-ness, or for portability, that your suggestion in that other thread was different? FWIW I'm working on a solution to that other thread today -- an update later I hope.

Thanks for clarification :) -- on with the show,

Sasha

ghostdog74 12-14-2009 09:45 AM

Quote:

Originally Posted by GrapefruiTgirl (Post 3790997)
@ Ghostdog, respectfully: your shell scripting help has many times proven very helpful to myself and others, and I appreciate that -- you're knowledgeable in this area, no question -- but on this subject of arrays, I'm getting a little bit of mixed messages from you. In this thread, you're suggesting use of arrays, yet in this other thread of mine you suggest I avoid (extensive use of) arrays and/or switch languages if I need a lot of array-like constructs :scratch: so why the difference? Was it the desire for POSIX-ness, or for portability, that your suggestion in that other thread was different? FWIW I'm working on a solution to that other thread today -- an update later I hope.

you misunderstood what i am trying to say in that thread. You mentioned you are starting a project which makes use of arrays, and that you worry about problems of shells not supporting arrays. Instead of worrying about how if you use arrays in your script and being not able to work for other shells that don't support it, I suggested to you to use a different programming language than the shell, such as Python (or Perl if you like). Python/Perl data types (arrays, variables, dictionaries/hashes) have been pretty standard since olden times, so you can be 99% sure that if you write your code in newer version of language, it can be used in older ones (data types/structures).

whereas coming back to this thread, its a different problem. OP is trying to set a variable name using another variable, which essentially in programming terms, is equivalent to assigning values to arrays.
consider this
Code:

a=0
int_$a=2

don't you think it cleaner to use arrays
Code:

declare -a array
i=0
array[$i]=2

now, whenever you need to call element 1's value, you just do array[0]. No need to invoke eval. Variables, after all, after just names for memory addresses, so are array indexes.

of course, if the OP's shell doesn't support arrays/assoc arrays, then too bad. use the eval method.

GrapefruiTgirl 12-14-2009 11:23 AM

OK, gotcha -- thanks for that clarification. To our detriment, I had not been clear enough in that other thread though: I should have made it more clear that I am not "just starting" that project, but rather it's been ongoing for a long time, and just lately, I began considering making it more portable, but it already has made extensive use of arrays, so I'm looking at a "conversion" issue, rather than starting a fresh project in a portable way.

My apology for the lack of clarity there.

Kind regards,
Sasha

ghostdog74 12-14-2009 05:34 PM

Ah, i see. If you are still going to continue writing in shell, there are some books that you can take reference to. eg "Beginning Portable shell scripting" etc. Or search on the internet for articles about that. But personally, i think it will be worthwhile to port your project to Python, (or Perl). Besides making use of their good data structures, there are vast amount of libraries you can use for your project without reinventing the wheel. anyway, its up to you.

chrism01 12-14-2009 05:44 PM

I can definitely confirm that arrays are one of the 3 basic data types (scalar, array, hash) in Perl & as he hinted, there's a huge library of pre-written modules avail at search.cpan.org.
Note that a lot of those are already in the std Perl install http://perldoc.perl.org/perlfaq3.htm...n-my-system%3F

konsolebox 12-17-2009 03:00 AM

Just want to add some more points as well. Using eval or ! is not bad in all forms. Sometimes there's no choice other than use them like when emulating multi-dimentional arrays.

We know that this is not possible:

Code:

a[0][1]=2
echo ${a[0][1]}

so sometimes we have to do things like this:

Code:

a=(a0 a1 a2 a3 a4)
a0[1]=2
eval echo \${${a[0]}}

we probably can make a cleaner version to that with associative arrays like

Code:

a["0,1"]=2
echo ${a["0,1"]}
i=0 j=1
echo ${a["$i,$j"]}  # correct me if the syntax of the index is incorrect.

but we know in associative arrays, we cannot associate many values as once as in indexed arrays and order of indices in associative arrays is never a guarantee. I'm not sure if it's sorted by default in bash.

Code:

a0=(value1 value2 value3 value4)
bvalues=<input from somewhere with values: value5 value6 value7 value8 in order>
b0=(${bvalues})
for A in ${a0[@]}; do ...

There are also many other situations where only indexed arrays can be applicable.

GrapefruiTgirl 12-17-2009 10:01 AM

Further to the above, simulating arrays, even multi-dimentional ones, *can* be done like this:
Code:

a[0][1][2]

would become:

a012 or a_0_1_2 (or however you want to write it). To put a value in there:

shell$ a012="element 0,1,2"

To do it using some arbitrary index:

shell$ x=2 # index
shell$ eval a01${x}="'element 0,1,2'"

to get an indexed value out:

shell$ eval echo \$a01${x}

further example with two indexes:

shell$ y=5;x=2
shell$ eval a0${y}${x}="'element 0,5,2'" # assign a value
shell$ eval echo \$a0${y}${x} # read the value

further example with 3 indexes:

shell$ z=6
shell$ eval a${z}${y}${x}="'element 6,5,2'" # assign a value
shell$ eval echo \$a${z}${y}${x} # read the value

NOTE: Be careful to use enough "quotes" when assigning multi-part strings to the 'arrays' this way. Unquoted multi-part strings/values will give an error when assigned like this.

Sasha

DevonB 12-18-2009 12:59 PM

Quote:

Originally Posted by GrapefruiTgirl (Post 3788477)
Hopefully this will help you:

Code:

sasha@reactor:~$ STRING1=MyName
sasha@reactor:~$ SOME_VALUE=Devon
sasha@reactor:~$ newvar=$(eval echo \${STRING2_$STRING1_REST_OF_STRING=$SOME_VALUE})
sasha@reactor:~$ echo $newvar
Devon
sasha@reactor:~$
sasha@reactor:~$ eval echo \${STRING2_$STRING1_REST_OF_STRING}           
Devon
sasha@reactor:~$

Sasha

...and it worked perfectly, thank you so much.

Devon


All times are GMT -5. The time now is 04:30 AM.