views:

187

answers:

4

I'm trying to understand if it's possible to create a set of variables that are numbered based on another variable (using eval) in a loop, and then call on it before the loop ends.

As an example I've written a script called question (The fist command is to show what is the contents of the variable $tab)

(23:32:12\[[email protected])
[~/bin]$ listQpsk 40|grep -w [1-4]
40 SMANHUBAQPSK1          1    1344      1195        88
40 SMANHUBAQPSK1          2    1668      1470        88
40 SMANHUBAQPSK1          3    1881      1539        81
40 SMANHUBAQPSK1          4    1686      1409        83


(23:18:42\[[email protected])
[~/bin]$ cat question
#!/usr/bin/bash
tab=`listQpsk 40|grep -w [1-4]`
seq=1
num=4
until [[ $seq -gt $num ]];do
eval count$seq=`echo "$tab"|grep -w $seq|awk '{print $5}'`
seq=$(($seq+1))
done
echo $count1
echo $count2
echo $count3
echo $count4

When I run this I get

(23:32:23\[[email protected])
[~/bin]$ ./question 
1195
1471
1538
1409

Which is exactly what I would expect, but is there a way to move the echo commands inside of the until loop so that part of the loop is echoing the value of the variable that was just created. Something like:

until [[ $seq -gt $num ]];do
eval count$seq=`echo "$tab"|grep -w $seq|awk '{print $5}'`
seq=$(($seq+1))
echo "$count$seq"
done

PS: Sorry if my formatting is off...first time posting here, and I only know markdown from reddit.

+1  A: 

Not exactly answering your question, but... did you know bash has array variables?

seq=1
num=4
until [[ $seq -gt $num ]];do
count[$seq]=`echo "$tab"|grep -w $seq|awk '{print $5}'`
seq=$(($seq+1))
done
echo ${count[*]}

Or without arrays:

seq=1
num=4
until [[ $seq -gt $num ]];do
eval count$seq=`echo "$tab"|grep -w $seq|awk '{print $5}'`
eval echo \$count$seq
seq=$(($seq+1))
done
John Kugelman
I'm aware of them, but I haven't really started working them into scripts yet. 0 Formal training + full time work as a sysadmin means that I generally have to learn new skills as I have a need for them. I try not to get too far ahead of myself, because I worry I won't absorb it. Awesome reply though. Seeing the array syntax in something I already mostly understand is a huge help in my general understanding.Other than cleanliness, is there an advantage in this instance? It's still the same amount of built-ins vs external commands no?
DesCo
I would consider it the "right" way to do this. However, the syntax can get kind of ugly, as evidenced by the `echo` statement. Without arrays you have to throw more evals at it (as per cma's answer). BTW, I've read the `man bash` page a dozen times top to bottom and I still find a new awesome "where have you been all my life" feature every time I read it again. ;-)
John Kugelman
A: 

Try this:

varName=a
for i in 1 2 3
do
   eval $varName$i=stuff
   eval var=\$$varName$i
   echo $var
done

some versions of shell also let you use ${!var} to indirectly reference variables

Charles Ma
That's the part he's already doing.
Dennis Williamson
Ah oops, fixed so it does what he wants now :)
Charles Ma
A: 

Yes, like this (in bash at least):

$ count1=xyz
$ seq=1
$ value=`eval echo \$\{count$seq\}`
$ echo $value
+1  A: 

Use indirection:

until [[ $seq -gt $num ]];do
    var="count$seq"
    eval $var=$(echo "$tab"|awk -v seq=$seq '$3==seq {print $5}') # awk loves to do grep's job
    let seq+=1    # another way
    echo "${!var}"    # indirection
done

No need for another eval.

Dennis Williamson
That worked perfectly. I'm not sure I understand the indirection part though. But it worked both the way you wrote it and just as echo $var
DesCo
echo $var would give "count1", for example. echo ${!var} gives the contents of the contents of var which would be "1195". echo ${!var} works similarly to echo $(eval echo \$$var)
Dennis Williamson