LinuxQuestions.org
Visit Jeremy's Blog.
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices


Reply
  Search this Thread
Old 10-12-2012, 05:15 PM   #1
bilyboy65
LQ Newbie
 
Registered: Apr 2012
Posts: 14

Rep: Reputation: 0
get var value when var name is part of another var


Hello,

I'm trying to write a script in bash.

I have a for loop

varlist="one two three"
one_DIR=/directory1
two_DIR=/directory2
three_DIR=/directory3

for var1 in varlist
do
cd $"$var1_DIR"
done

var1 will contain part of a name to another variable that I want to get a value of. So I know the above code is wrong, but it illustrates what I'm trying to do.

I want to change to a dir stored in the n_DIR variable and use the value in var1 to get the variable name.

Is there a way to do this or should I abandon this plan and figure out another way?

Thank you for any help.
 
Old 10-12-2012, 05:29 PM   #2
suicidaleggroll
LQ Guru
 
Registered: Nov 2010
Location: Colorado
Distribution: OpenSUSE, CentOS
Posts: 5,561

Rep: Reputation: 2127Reputation: 2127Reputation: 2127Reputation: 2127Reputation: 2127Reputation: 2127Reputation: 2127Reputation: 2127Reputation: 2127Reputation: 2127Reputation: 2127
Code:
#!/bin/bash

varlist="one two three"
one_DIR=/directory1
two_DIR=/directory2
three_DIR=/directory3

for var1 in $varlist; do
  varname=${var1}_DIR
  cd "${!varname}"
done
 
Old 10-12-2012, 05:38 PM   #3
colucix
LQ Guru
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,509

Rep: Reputation: 1978Reputation: 1978Reputation: 1978Reputation: 1978Reputation: 1978Reputation: 1978Reputation: 1978Reputation: 1978Reputation: 1978Reputation: 1978Reputation: 1978
Indirect variable reference.
Code:
for var1 in $varlist
do
  my_var=${var1}_DIR
  cd ${!my_var}
done
First it builds the name of the variable based on the current value of var1, then indirectly references the variable and gives you the desired result.

Edit: oops... too late! Sorry for redundancy.

Last edited by colucix; 10-12-2012 at 05:39 PM.
 
Old 10-13-2012, 12:21 PM   #4
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian + kde 4 / 5
Posts: 6,837

Rep: Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981
Please use ***[code][/code]*** tags around your code and data, to preserve the original formatting and to improve readability. Do not use quote tags, bolding, colors, "start/end" lines, or other creative techniques.

Indirect variables are not a generally recommended practice. It makes the code obscure. Modern shells usually have better ways to do most of the same jobs.

How can I use variable variables (indirect variables, pointers, references) or associative arrays?
http://mywiki.wooledge.org/BashFAQ/006

In addition, you should not store lists of things in a single variable. That's what arrays are for.


In this case, I think all you should really need is a single regular array.

Code:
dirlist=( /directory1 /directory2 /directory3 )

for var in 0 1 2 ; do
	cd "${dirlist[var]}"
done
Remember that arrays start at index 0.

You could work with intermediate variables too, if you wanted, such as

Code:
one=0
cd "${dirlist[one]}".
But a stronger option, if you really need to use strings like "one, two, three", would be to use bash's associative arrays; where the array index is a text string (or a variable containing a text string), rather than an integer.

Code:
declare -A dirlist

dirlist[one]=/directory1
dirlist[two]=/directory2
dirlist[three]=/directory3

for var in one two three; do
	cd "${dirlist[$var]}"
done
Notice that since the index is now a string, The "[]" field is no longer operating as an arithmetic environment, and so the variable needs to have a dollar sign attached to it.
 
Old 10-15-2012, 12:19 PM   #5
bilyboy65
LQ Newbie
 
Registered: Apr 2012
Posts: 14

Original Poster
Rep: Reputation: 0
David - Thank you for the help, but I choose a string list for a number of reasons. Maybe I just don't know a trick to accomplish this using array's in bash. But mainly I chose not to use an array because I need to identify what values have been set and the kernal I'm using doesn't allow for the associative arrays (and I can't change this). I read through the links you posted and didn't see an alternative to what i need to accomplish. Searching a string seems to be faster then looping on an array to match a value. I also can't use a hard coded list of directories because that changes with each box being accessed. These have to be setup as parameters. I think the only answer for me is to indirectly access the variable value.

I do appreciate the info on the code tags. I was not aware of those but will be using them in the future.
 
Old 10-15-2012, 12:21 PM   #6
bilyboy65
LQ Newbie
 
Registered: Apr 2012
Posts: 14

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by suicidaleggroll View Post
Code:
#!/bin/bash

varlist="one two three"
one_DIR=/directory1
two_DIR=/directory2
three_DIR=/directory3

for var1 in $varlist; do
  varname=${var1}_DIR
  cd "${!varname}"
done
Thank you this is the solution i went with and everything works.
 
Old 10-20-2012, 10:35 AM   #7
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian + kde 4 / 5
Posts: 6,837

Rep: Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981
Quote:
Originally Posted by bilyboy65 View Post
But mainly I chose not to use an array because I need to identify what values have been set and the kernal I'm using doesn't allow for the associative arrays (and I can't change this).
What does the kernel have to do with this? This is entirely a shell syntax problem. bash has included support for regular arrays from v.3, and associative arrays from v.4. Unless you aren't using bash at all (or ksh, or another shell that supports arrays).


Quote:
I read through the links you posted and didn't see an alternative to what i need to accomplish. Searching a string seems to be faster then looping on an array to match a value.
One of the main weaknesses with indirect variables is that variable names can only include letters, numbers, and the underscore, and cannot begin with a number. So if the value of var1 included anything outside of that pattern, then "${!varname}" would not give you a valid value.

But if you are defining the variable names/indexes entirely in the script, then this should really be a non-issue, since the problem only occurs if the variable names are defined from outside. If you are only using the names internally, there should be little need for any kind of indirection.

Associative arrays don't suffer from this problem, naturally, as any string can be used as the index, and of course regular arrays simply use numbers to specify the entry.

And I only used a loop for my examples because that's what you used. There's no need to loop through anything if you know the actual value you need to call.

(
PS: Actually, varlist is a place where you should be using an array over a single variable. Again, scalar arrays are not designed for storing lists of things.

Code:
varlist=( one two three )
for var1 in "${varlist[@]}"; do
	...
)

Quote:
I also can't use a hard coded list of directories because that changes with each box being accessed. These have to be setup as parameters. I think the only answer for me is to indirectly access the variable value.
I see no problem here either. Shell arrays are just another type of parameter. All you have to do is set the one to the other.

Code:
dirarray=( "$1" "$2" "$3" )

printf '%s\n' "${dirarray[@]}"	#prints all existing array values, one per line

cd "${dirarray[2]}"		#changes to the directory given in parameter $3, in this case.
In short, while I don't have full knowledge of what you are trying to do, I see nothing posted so far that would necessarily favor indirect variables over arrays.
 
Old 10-20-2012, 10:36 PM   #8
bilyboy65
LQ Newbie
 
Registered: Apr 2012
Posts: 14

Original Poster
Rep: Reputation: 0
Quote:
What does the kernel have to do with this? This is entirely a shell syntax problem. bash has included support for regular arrays from v.3, and associative arrays from v.4. Unless you aren't using bash at all (or ksh, or another shell that supports arrays).

dirlist[one]=/directory1
dirlist[two]=/directory2
dirlist[three]=/directory3
Using arrays would make my life much easier, but it's just not working for me. I'm using bash and if I enter the code above that you gave me before and type set to see how it's defined; it's not defined as typed. It's defined as following

Code:
dirlist[0]=/directory1
dirlist[1]=/directory2
dirlist[2]=/directory3
I did a lot of research on this and the syntax for bash seems to be as you stated before or as

Code:
declare -A dirlist
however all of these places seem to say that it's only included in bash v4. If i do a man declare there is no -A option and I get an error when running it using bash 3.2.25.
So that is not an option for me it seems. If it was then I wouldn't even be asking about how to use indirection.

I'm not worried about what is stored in the variable for the indirection because it's all internal. Users do not have a way to change these values.
 
Old 10-21-2012, 05:37 AM   #9
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian + kde 4 / 5
Posts: 6,837

Rep: Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981Reputation: 1981
I'm at a loss to see why it isn't working for you. bash 3.2 definitely has regular (numerically-indexed) arrays, although not associative ones. So the "0,1,2" indexed version should be working, at least, but the "one,two,three" one will not.


But what I'm really questioning is whether you need to have "word string" style variables at all, especially since you state that the whole thing is internal. I still suggest that a regular array would suit you just fine. You could even define the indexes it so that the index numbers start with 1 instead of 0.

Code:
dirs=( [1]=/directory1 [2]=/directory2 [3]=/directory3 )

#print individual entries by index number
echo "The first directory is ${dirs[1]}"
echo "The second directory is ${dirs[2]}"
echo "The third directory is ${dirs[3]}"

#loop and print all entries by value
for dir in "${dirs[@]}"; do
	echo "The directory is $dir"
done

#loop and print all entries by index number
for dir in "${!dirs[@]}"; do
	echo "The current directory is ${dirs[dir]}"
done
And if you really want to use word strings, then you can define variables that expand to the index numbers you want, in a kind of simulated associative array. This would be hard to do safely if the index values could come from outside, but it's not problem in a controlled situation like this.

Code:
one=1
two=2
three=3

echo "The first directory is ${dirs[one]}"
echo "The second directory is ${dirs[two]}"
echo "The third directory is ${dirs[three]}"

for dir in one two three; do
	echo "The directory is ${dirs[dir]}"
done
But anyway, if you feel more comfortable using indirect references, I'm not going to argue it any more. It's your code after all.
 
Old 10-21-2012, 10:32 AM   #10
bilyboy65
LQ Newbie
 
Registered: Apr 2012
Posts: 14

Original Poster
Rep: Reputation: 0
I appreciate the arguing. It makes me a better programmer and gives me new ways to think about things. And I think with your last idea about assigning numbers to strings gave me an idea of how I can change all of the affected code to use regular arrays. I don't think assigning numbers to strings will be the solution, but it put me on the right path. Who says arguing is a bad thing? Thank you for discussing with me.

Last edited by bilyboy65; 10-21-2012 at 10:33 AM.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
/var/cache/yum and /var/lib/rpm getting BIG. How to safely pare down? SharpyWarpy Linux - General 3 02-29-2012 02:17 AM
What to delete in /var dir if size of /var directory is 98%? manalisharmabe Linux - Newbie 6 10-15-2011 01:20 PM
my.cnf on debian squeeze. var names don't match, var values missing. sneakyimp Linux - Server 1 07-03-2011 02:59 AM
pam does not like my owner, group and date for /var/ftp. especially /var manis2008 Linux - Software 1 02-08-2008 08:36 AM
Moving /var/adm and /var/lib - why does it hurt? J_Szucs Linux - General 1 09-15-2004 07:46 PM

LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie

All times are GMT -5. The time now is 12:18 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration