bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Problem with how to assign an array


From: Steven W. Orr
Subject: Re: Problem with how to assign an array
Date: Thu, 24 Feb 2011 18:59:02 -0500
User-agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.13) Gecko/20101207 Thunderbird/3.1.7

Ok. Thanks for reading and responding. I thought I expressed myself but I see that I left too much out. I'll amplify below.


On 2/24/2011 3:42 PM, Greg Wooledge wrote:
On Thu, Feb 24, 2011 at 02:55:13PM -0500, Steven W. Orr wrote:
I have three arrays

a1=(aaa bbb ccc ddd)
a2=(qqq www eee rrr)
a3=(fff ggg hhh)

I then set a_all

a_all=("${a1[*]}" "${a2[*]}" "${a3[*]}"

Yes, I forgot the closing paren.

a_all=("${a1[*]}" "${a2[*]}" "${a3[*]}")

I intentionally used the star instead of the atsign because I'm taking advantage of the fact that these array elements all have no whitespace. So, after the assignment to a_all, the value of a[0] is equal to the single string represented by "${a1[*]}" (with quotes).

If I were to use the atsign then I lose the boundaries of what was contributed by each of a1, a2 and a3. By selecting *which* index to use into a_all and assigning that value to real_a and deliberately not using quotes

real_a=( ${a_all[index]} )

I get all of the values I want in real_a.

I apologize for not making it clear, but the whole thing does depend on the values not containing any whitespace.

Now the wrinkle comes into play:

I need the values of a1 a2 and a3 to be allowed to contain possible null values (which I coded up as '').

The problem is that when I make my assignment to a_all, my null value 
disappears.

Instead of assigning

a_all=("${a1[*]}" "${a2[*]}" "${a3[*]}")

is it possible instead to say something like this:

a_all=(a1 a2 a3)

and then later when I calculate my index, use a fancy eval to get me what I 
want?

For example, I can say:

513 > a1=(aa1 aa2 aa3)
514 > a2=(aa21 aa22 aa23)
515 > a3=(aa31 aa32 aa33 aa34)
516 > a_all=(a1 a2 a3)
517 > r=($(eval echo "\${${a_all[1]}[@]}"))
518 > echo "${r[@]}"
aa21 aa22 aa23
*519 > echo ${#r[@]}
3

which is correct. But if I change a2 to contain a null value, I lose it:

520 > a2=(aa21 aa22 '' aa23)
521 > r=($(eval echo "\${${a_all[1]}[@]}"))
522 > echo ${#r[@]}
3
*523 > echo "${r[@]}"
aa21 aa22 aa23

instead of the 4 values that I want.

(many hours pass...)

I came up with a solution that works. I offer it up for posterity and as an apology for not being clear before. :-(

#! /bin/bash

a1=(
    SLES10      sles-10         sles10  0       '' wahoo
    RHEL5       rhel-5          rhel5   1
                        'stuffwith|areserved|delim|forlater' foobar
)
a2=(
    SLES11      sles-11         sles11  0       '')
a3=(
    SLES11SP1   sles-11-sp1     sles11sp1       0       ''
    RHEL6       rhel-6          rhel6           1       ''
    RHEL6q      rhel-6q         rhel6q          3       '')
a_all=(
    "${a1[@]}"
    "${a2[@]}"
    "${a3[@]}" )
ddsizes=( "${#a1[@]}"
    "${#a2[@]}"
    "${#a3[@]}" )
echo "ddsizes:${#ddsizes[@]}:${ddsizes[@]}"
ddstarts=(0)
curr=0
for (( ii=0; ii < ${#ddsizes[@]}; ii++ ))
do
    ddstarts+=( $(( ${ddsizes[ii]} + curr )) )
    (( curr+=ddsizes[ii] ))
done
echo "ddstarts:${ddstarts[@]}"

for ((ii=0; ii<2; ii++
do
    real_a=("${a_all[@]:${ddstarts[ii]}:${ddstarts[ii+1]}-${ddstarts[ii]}}")
    echo "real_a:${#real_a[@]}:${real_a[@]}"
done







Missing ).  Also, a far more serious problem, you used * when you should
have used @.

a_all=("${a1[@]}" "${a2[@]}" "${a3[@]}")

This is absolutely critical.  Without this, you are no longer maintaining
the integrity of each element.  In fact, what you've got there will create
a_all with precisely 3 elements.  Each of these elements will be a
concatenation of the other arrays' elements with a space (or the first
char of IFS if you've set that) between them.

Later on, I decide which element of a_all I really want. So with my new
index calculated, I say

real_a=( ${a_all[index]} )

This is also wrong.  This one does word-splitting on the element you're
indexing, and the resulting set of words becomes a new array.

In fact, I can only guess what you're trying to do here.

If you want to assign a single element to a scalar variable, you
should do:  element=${array[index]}

And it worked really well until today. The problem is that I need an
element of the aNs to be allowed to be null values.

No problem.

Like this:

a1=(aaa bbb ccc ddd '' jjj kkk lll)

No problem.

such that if index is 0, I'd like real_a to end up with 8 elements instead
of 7.

Huh?  You mean during the concatenation?  (You changed the array name?)
Do it correctly:

imadev:~$ unset a1 a2 big; a1=(a b '' c) a2=(d e f '')
imadev:~$ big=("${a1[@]}" "${a2[@]}")
imadev:~$ printf "<%s>  " "${big[@]}"; echo
<a>  <b>  <>  <c>  <d>  <e>  <f>  <>

I could create a sentinel, I could use a case statement, I could create all
kinds of confabulations, but I'd like to know if there's a better way to do
it.

Huh?

I literally tried everything I could think of.

You must learn the difference between "$*" and "$@".  (And the analogous
treatment of * and @ in an array indexing context.)

imadev:~$ wrong=("${a1[*]}" "${a2[*]}")
imadev:~$ printf "<%s>  " "${wrong[@]}"; echo
<a b  c>  <d e f>

If you don't use the right syntax, you're going to have problems with
elements that contain whitespace (or IFS characters) as well as empty
elements as you already noted.


--
Time flies like the wind. Fruit flies like a banana. Stranger things have  .0.
happened but none stranger than this. Does your driver's license say Organ ..0
Donor?Black holes are where God divided by zero. Listen to me! We are all- 000
individuals! What if this weren't a hypothetical question?
steveo at syslang.net



reply via email to

[Prev in Thread] Current Thread [Next in Thread]