(M)  s i s t e m a   o p e r a c i o n a l   m a g n u x   l i n u x ~/ · documentação · suporte · sobre

 

3.22. Arrays

Newer versions of bash support one-dimensional arrays. Arrays may be declared with the variable[xx] notation or explicitly by a declare -a variable statement. To dereference (find the contents of) an array variable, use curly bracket notation, that is, ${variable[xx]}.

Example 3-89. Simple array usage

#!/bin/bash


area[11]=23
area[13]=37
area[51]=UFOs

# Note that array members need not be consecutive
# or contiguous.

# Some members of the array can be left uninitialized.
# Gaps in the array are o.k.


echo -n "area[11] = "
echo ${area[11]}
echo -n "area[13] = "
echo ${area[13]}
# Note that {curly brackets} needed
echo "Contents of area[51] are ${area[51]}."

# Contents of uninitialized array variable print blank.
echo -n "area[43] = "
echo ${area[43]}
echo "(area[43] unassigned)"

echo

# Sum of two array variables assigned to third
area[5]=`expr ${area[11]} + ${area[13]}`
echo "area[5] = area[11] + area[13]"
echo -n "area[5] = "
echo ${area[5]}

area[6]=`expr ${area[11]} + ${area[51]}`
echo "area[6] = area[11] + area[51]"
echo -n "area[6] = "
echo ${area[6]}
# This doesn't work because
# adding an integer to a string is not permitted.

echo
echo
echo

# -----------------------------------------------------------------
# Another array, "area2".
# Another way of assigning array variables...
# array_name=( XXX YYY ZZZ ... )

area2=( zero one two three four)

echo -n "area2[0] = "
echo ${area2[0]}
# Aha, zero-based indexing (first element of array is [0], not [1]).

echo -n "area2[1] = "
echo ${area2[1]}  # [1] is second element of array.
# -----------------------------------------------------------------


echo
echo
echo

# -----------------------------------------------
# Yet another array, "area3".
# Yet another way of assigning array variables...
# array_name=([xx]=XXX [yy]=YYY ...)

area3=([17]=seventeen [24]=twenty-four)

echo -n "area3[17] = "
echo ${area3[17]}

echo -n "area3[24] = "
echo ${area3[24]}
# -----------------------------------------------


exit 0

Arrays variables have a syntax all their own, and even standard bash operators have special options adapted for array use.

Example 3-90. Some special properties of arrays

#!/bin/bash

declare -a colors
# Permits declaring an array without specifying size.

echo "Enter your favorite colors (separated from each other by a space)."

read -a colors
# Special option to 'read' command,
# allowing it to assign elements in an array.

echo

  element_count=${#colors[@]} # Special syntax to extract number of elements in array.
# element_count=${#colors[*]} works also.
index=0

# List all the elements in the array.
while [ $index -lt $element_count ]
do
  echo ${colors[$index]}
  let "index = $index + 1"
done
# Each array element listed on a separate line.
# If this is not desired, use  echo -n "${colors[$index]} "

echo

# Again, list all the elements in the array, but using a more elegant method.
  echo ${colors[@]}
# echo ${colors[*]} works also.


echo

exit 0

As seen in the previous example, either ${array_name[@]} or ${array_name[*]} refers to all the elements of the array. Similarly, to get a count of the number of elements in an array, use either ${#array_name[@]} or ${#array_name[*]}.

--

Arrays permit deploying old familiar algorithms as shell scripts. Whether this is necessarily a good idea is left to the reader to decide.

Example 3-91. An old friend: The Bubble Sort

#!/bin/bash

# Bubble sort, of sorts.

# Recall the algorithm for a bubble sort. In this particular version...

# With each successive pass through the array to be sorted,
# compare two adjacent elements, and swap them if out of order.
# At the end of the first pass, the "heaviest" element has sunk to bottom.
# At the end of the second pass, the next "heaviest" one has sunk next to bottom.
# And so forth.
# This means that each successive pass needs to traverse less of the array.
# You will therefore notice a speeding up in the printing of the later passes.


exchange()
{
  # Swaps two members of the array.
  local temp=${Countries[$1]} # Temporary storage for element getting swapped out.
  Countries[$1]=${Countries[$2]}
  Countries[$2]=$temp
  
  return
}  

declare -a Countries  # Declare array, optional here since it's initialized below.

Countries=(Netherlands Ukraine Zair Turkey Russia Yemen Syria Brazil Argentina Nicaragua Japan Mexico Venezuela Greece England Israel Peru Canada Oman Denmark Wales France Kashmir Qatar Liechtenstein Hungary)
# Couldn't think of one starting with X (darn).

clear  # Clear the screen to start with. 

echo "0: ${Countries[*]}"  # List entire array at pass 0.

number_of_elements=${#Countries[@]}
let "comparisons = $number_of_elements - 1"

count=1 # Pass number.

while [ $comparisons -gt 0 ]   # Beginning of outer loop
do

  index=0  # Reset index to start of array after each pass.

  while [ $index -lt $comparisons ] # Beginning of inner loop
  do
    if [ ${Countries[$index]} \> ${Countries[`expr $index + 1`]} ]
    # If out of order...
    # Recalling that \> is ASCII comparison operator.
    then
      exchange $index `expr $index + 1`  # Swap.
    fi  
    let "index += 1"
  done # End of inner loop
  

let "comparisons -= 1"
# Since "heaviest" element bubbles to bottom, we need do one less comparison each pass.

echo
echo "$count: ${Countries[@]}"
# Print resultant array at end of each pass.
echo
let "count += 1"   # Increment pass count.

done  # End of outer loop

# All done.

exit 0

--

Arrays enable implementing a shell script version of the Sieve of Erastosthenes. Of course, a resource-intensive application of this nature should really be written in a compiled language, such as C. It runs excruciatingly slowly as a script.

Example 3-92. Complex array application: Sieve of Erastosthenes

#!/bin/bash

# sieve.sh
# Sieve of Erastosthenes
# Ancient algorithm for finding prime numbers.

# This runs a couple of orders of magnitude
# slower than equivalent C program.

LOWER_LIMIT=1
# Starting with 1.
UPPER_LIMIT=1000
# Up to 1000.
# (You may set this higher...
#  if you have time on your hands.)

PRIME=1
NON_PRIME=0

let SPLIT=UPPER_LIMIT/2
# Optimization:
# Need to test numbers only
# halfway to upper limit.


declare -a Primes
# Primes[] is an array.


initialize ()
{
# Initialize the array.

i=$LOWER_LIMIT
until [ $i -gt $UPPER_LIMIT ]
do
  Primes[i]=$PRIME
  let "i += 1"
done
# Assume all array members guilty (prime)
# until proven innocent.
}

print_primes ()
{
# Print out the members of the Primes[] array
# tagged as prime.

i=$LOWER_LIMIT

until [ $i -gt $UPPER_LIMIT ]
do

  if [ ${Primes[i]} -eq $PRIME ]
  then
    printf "%8d" $i
    # 8 spaces per number
    # gives nice, even columns.
  fi
  
  let "i += 1"
  
done

}

sift ()
{
# Sift out the non-primes.

let i=$LOWER_LIMIT+1
# We know 1 is prime, so
# let's start with 2.

until [ $i -gt $UPPER_LIMIT ]
do

if [ ${Primes[i]} -eq $PRIME ]
# Don't bother sieving numbers
# already sieved (tagged as non-prime).
then

  t=$i

  while [ $t -le $UPPER_LIMIT ]
  do
    let "t += $i "
    Primes[t]=$NON_PRIME
    # Tag as non-prime
    # all multiples.
  done

fi  

  let "i += 1"
done  


}


# Invoke the functions sequentially.
initialize
sift
print_primes
echo
# This is what they call structured programming.

exit 0