LinuxQuestions.org
Support LQ: Use code LQ3 and save $3 on Domain Registration
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices



Reply
 
Search this Thread
Old 06-04-2012, 07:30 AM   #1
c_henry
LQ Newbie
 
Registered: Jan 2008
Posts: 6

Rep: Reputation: 0
BASH: Assign a variable to a variable name...


Hi,

Apologies for the possibly confusing thread title in advance.

I'm trying to read in a variable then use that variable in a variable name. My specific problem is something like this:

EBS_GW=192.168.0.1
OBIE_GW=192.168.1.1

echo "What is the product: "
read PROD

echo "The gateway for $PROD is $PROD_GW"

So if the user entered EBS, they would get the EBS_GW value of 192.168.0.1.

I've tried the eval command, but I'm still not getting it right.

Any help is appreciated.

Many thanks,

Colin
 
Old 06-04-2012, 08:10 AM   #2
pan64
Guru
 
Registered: Mar 2012
Location: Hungary
Distribution: debian i686 (solaris)
Posts: 5,169

Rep: Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364
Try this:
eval echo "The gateway for $PROD is \$${PROD}_GW"
 
1 members found this post helpful.
Old 06-04-2012, 08:29 AM   #3
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 943Reputation: 943Reputation: 943Reputation: 943Reputation: 943Reputation: 943Reputation: 943Reputation: 943
What are you trying to accomplish? Variable variables are the wrong answer. (I say that because I have not yet seen a case where they are the right answer.)

Assume you have a separate file, say /etc/gateway.list:
Code:
EBS	192.168.0.1
OBIE	192.168.1.1
Now you can do e.g.
Code:
GW=""
while [ -z "$GW" ]; do
    read -p 'Product? ' PROD

    # Exit if empty product
    [ -n "$PROD" ] || exit 0

    # Locate product in gateway list
    while read NAME IP COMMENT ; do
        if [ "$NAME" = "$PROD" ]; then
            GW="$IP"
            break
        fi
    done < /etc/gateway.list

    [ -n "$GW" ] || printf 'Product %s: No gateway found.\n' "$PROD"
done
which aborts the script cleanly if the user supplies an empty string for the product name.

I prefer to keep my syntax POSIX-compatible, but if you use Bash only, then you should probably use the [[ ... ]] compound command for the conditional expressions; see the Bash Reference Manual, Conditional Expressions chapter for details. The above snippet is written in a way which would allow it to work with both Bash and POSIX shells like dash. (I normally would use awk to pick the IP address, but I decided to keep the above strictly within the shell, avoiding any external dependencies.)

If you don't want to have a separate file, replace the done < /etc/gateway.list line with a here document, e.g.
Code:
    done <<ENDOFLIST
        EBS	192.168.0.1
        OBIE	192.168.1.1
ENDOFLIST
Note that ENDOFLIST must not be indented. (You can indent it with tabs if you use <<-ENDOFLIST, but since many editors convert tabs to spaces, and spaces will not work for the indentation, it is always simpler to put it in the first column even if it breaks indentation visually.)

A completely different approach in Bash is to have an array of IP addresses. Bash version 4 and later support associative arrays. To be compatible with older versions, you can just use an array with elements combining both name and address, i.e.
Code:
gateways=('EBS=192.168.0.1' 'OBIE=192.168.1.1')
in which case the loop to find the address matching PROD in the array would be
Code:
for entry in "${gateways[@]}" ; do
    if [ "$PROD" = "${entry%%=*}" ]; then
        GW="${entry#*=}"
        break
    fi
done
where ${entry%%=*} evaluates to the current value of entry with everything after the first = removed, and ${entry#*=} evaluates to the value of entry with everything up to and including the first = removed. (The value of entry itself is not affected.) Note that this works fine with IPv6 addresses, too. It is the reason why I used = instead of : as the separator in the list.

So, what are you trying to accomplish?
 
1 members found this post helpful.
Old 06-04-2012, 08:36 AM   #4
c_henry
LQ Newbie
 
Registered: Jan 2008
Posts: 6

Original Poster
Rep: Reputation: 0
Brilliant that works.

Just one more, how would I assign that to a new variable?

Say once I found what the value it got evaluated to, then I wanted to assign it to say $DEFAULT_GW?

I've tried:

DEFAULT_GW=`eval echo "\$${PROD}_GW"`
echo "DEFAULT_GW is: $DEFAULT_GW

but I get

DEFAULT_GW is: 13219{PROD}_GW

Which I'm guessing is the PID.

Really appreciated the quick reply and hope I'm not pushing my luck (and more importantly your goodwill) too much.

Colin

Last edited by c_henry; 06-04-2012 at 08:37 AM. Reason: Replying to wrong message
 
Old 06-04-2012, 08:46 AM   #5
pan64
Guru
 
Registered: Mar 2012
Location: Hungary
Distribution: debian i686 (solaris)
Posts: 5,169

Rep: Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364Reputation: 1364
maybe:
eval "DEFAULT_GW=\$${PROD}_GW"
but maybe better to use a solution similar to the one described by Nominal Animal. You will hardly be able to check errors...
 
1 members found this post helpful.
Old 06-04-2012, 08:55 AM   #6
c_henry
LQ Newbie
 
Registered: Jan 2008
Posts: 6

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by Nominal Animal View Post
What are you trying to accomplish?
Pretty much what you've just described!
 
Old 06-04-2012, 08:57 AM   #7
c_henry
LQ Newbie
 
Registered: Jan 2008
Posts: 6

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by pan64 View Post
maybe:
eval "DEFAULT_GW=\$${PROD}_GW"
but maybe better to use a solution similar to the one described by Nominal Animal. You will hardly be able to check errors...
That also works a treat.

Thank you so much.
 
Old 06-04-2012, 09:32 AM   #8
grail
Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 7,698

Rep: Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988Reputation: 1988
Here are some reasons not to use eval (ever if you can help it)

I was wondering why this had to be so complicated? What was wrong with:
Code:
#!/bin/bash

DEFAULT=10.1.1.1
EBS=192.168.0.1
OBIE=192.168.1.1

echo "What is the product: "
read PROD

echo "Your gateway choice is: ${!PROD:-$DEFAULT}"
Obviously NA has pointed out that you need to incorporate some testing (I have included a type of work around) to make sure the user enters something relevant
 
Old 06-04-2012, 09:41 AM   #9
rknichols
Senior Member
 
Registered: Aug 2009
Distribution: CentOS
Posts: 1,626

Rep: Reputation: 677Reputation: 677Reputation: 677Reputation: 677Reputation: 677Reputation: 677
Quote:
Originally Posted by pan64 View Post
maybe:
eval "DEFAULT_GW=\$${PROD}_GW"
but maybe better to use a solution similar to the one described by Nominal Animal. You will hardly be able to check errors...
Passing unfiltered user input to eval is extremely dangerous. You've just made it very simple for that user to get arbitrary commands executed. Consider this (user input in red):
Code:
read PROD
(ls *) #
eval "DEFAULT_GW=\$${PROD}_GW"
That will execute "ls *" in the current directory and capture the output in DEFAULT_GW. The ls command is, of course, fairly harmless, but any command could have been entered there.
 
Old 06-04-2012, 12:33 PM   #10
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Rep: Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950Reputation: 1950
As NominalAnimal said, variable variables are almost always the wrong answer.

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

And eval is just a variation of evil, in most cases. It's like digging a hole in your garden with an a-bomb. Just don't use it.


One of the biggest problems with trying to use variable variables is that legal variable names in the shell can only contain letters, numbers and the underscore, and cannot start with a number. You'd have to either test or convert any string you get beforehand if you wanted to use them. Much better would be to use an associative array, as described in the above link (and assuming bash or ksh), or just redesign everything to avoid needing them at all, if possible.


Code:
#!/bin/bash

declare -A address

address[EBS]=192.168.0.1
address[OBIE]=192.168.1.1

read -r -p "please enter the product name: " prod

if [[ -n "${address[$prod]}" ]] ; then

	echo "The gateway for $prod is "${address[$prod]}"

else

	echo "There's no gateway matching the product name $prod".

fi

Last edited by David the H.; 06-04-2012 at 12:45 PM. Reason: Some minor fixes
 
  


Reply

Tags
bash, evaluation, pointers, variables


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
Bash scripting...need to read a value from a file then assign to variable trekgirl Programming 9 02-28-2011 12:42 AM
bash script: how to assign command ouput to a variable without executing it? bostonantifan Programming 1 02-13-2011 12:55 AM
[SOLVED] [bash] assign boolean expression to variable hashbang#! Programming 10 08-16-2009 09:44 AM
How do you assign a variable to be a variable file name in a directory? David_Elliott Programming 4 04-14-2009 11:19 AM
bash script: how to assign an output (not the result) to a variable? Singing Banzo Programming 8 10-01-2006 07:29 PM


All times are GMT -5. The time now is 04:54 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
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration