Question on iterating array elements

Hi,

I am trying to do something similar to the for loop example from KSH For Loop Array: Iterate Through Array Values

$: cat y.ksh
#!/bin/ksh
# set array called nameservers
set -A nameservers 192.168.1.1 192.168.1.5 202.54.1.5

# print all name servers
for i in ${nameservers[@]}
do
        echo $i
done
$: ./y.ksh
192.168.1.1
192.168.1.5
202.54.1.5

My test script looks like below:

#!/bin/ksh
#
#

set -A arrSID
set -A arrVERSION

arrVERSION[1]="Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production"
arrVERSION[2]="Oracle9i Enterprise Edition Release 9.2.0.8.0 - 64bit Production"

echo
echo
for i in ${arrVERSION[@]}
do
   echo $i
done
echo
echo

It's output when I run it is as below:

$: ./x.ksh


Oracle
Database
11g
Enterprise
Edition
Release
11.2.0.4.0
-
64bit
Production
Oracle9i
Enterprise
Edition
Release
9.2.0.8.0
-
64bit
Production

I managed to use the while loop below and manage to get the output that I wanted.

$: ./z.ksh
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
Oracle9i Enterprise Edition Release 9.2.0.8.0 - 64bit Production
$: cat z.ksh
#!/bin/ksh
#
#

set -A arrSID
set -A arrVERSION

arrVERSION[1]="Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production"
arrVERSION[2]="Oracle9i Enterprise Edition Release 9.2.0.8.0 - 64bit Production"

i=1
while [[ $i -le ${#arrVERSION[@]} ]]
do
   echo ${arrVERSION[$i]}
   (( i=i+1 ))
done

exit 0

I just want to know why the for loop, i.e. the x.ksh, does not work like I expect it to be? I am guessing it is due to the spaces in the string. Is there any way around it. I just thought it is easier to use the for loop instead of the while loop.

Anyway, any feedback much appreciated. Thanks.

You could use the array indices in the for loop:

for i in ${!arrVERSION[*]}
do
   echo "${arrVERSION[$i]}"
done

Try quoting:

for i in "${arrVERSION[@]}"
  do echo $i
  done

The construct "${array[@]}" expands to all elements of this array. Note that also the construct "${array[]}" is expanded to all the array elements. The difference of these seemingly identical constructs is the used separating character. "${arr[@]}" uses an IFS character, "${arr[]}" does not.

You will not see a difference in the following call:

arr[1]="one two three"
arr[2]="four five six"

print - "-------- Using the asterisk:"
for i in ${arr[*]} ; do
     print - $i
done

print - "-------- Using the ampersand:"
for i in ${arr[@]} ; do
     print - $i
done

# ./arrtest.sh:
-------- Using the asterisk:
one
two
three
four
five
six
-------- Using the asterisk:
one
two
three
four
five
six

But once you quote properly (notice the double quotes around the variables to be expanded):

arr[1]="one two three"
arr[2]="four five six"

print - "-------- Using the asterisk:"
for i in "${arr[*]}" ; do
     print - $i
done

print - "-------- Using the asterisk:"
for i in "${arr[@]}" ; do
     print - $i
done


# ./arrtest.sh 
-------- Using the asterisk:
one two three four five six
-------- Using the asterisk:
one two three
four five six

The reason i sthe way the shell parses its input: in a first step all the variables are expanded, So from the line

for i in "${arr[@]}" ; do

The shell creates:

for i in "one two three[IFS-char]four five six" ; do

In a second step this is fed to the (internal) "for"-command, which evaluates this again. At this point " " (blank) and "[IFS]" (which, per default, is a blank too) have no difference and therefore get mixed up: this is why the first example produced each word on a separate line. Once you protect this line (by quoting it) from the shells interpretation it gets read correctly - at least with the "@" because the "*" now has another (and in your case equally unintended) meaning.

I hope this helps.

bakunin