06. Arrays and Strings (Part 1)

Overview

  • Often a script will need to work with a set of multiple data values
  • These data values can be input from the user or can be from the output of a utility through a pipe
  • It is useful to group these multiple data values into an array so we can easily refer to them as one group of data
  • The shell has multiple operations to support array manipulation
  • Similar to an array, a string is made up of multiple characters
  • Often we want to edit or extract just a part of the string
  • The shell has multiple operations to support string manipulation
  • Topics
    • Array operations
    • String manipulation operations

Creating / Initializing Array

  • The bash shell supports one dimensional arrays
  • An array can contain more than one type of data (both numeric values and strings can be stored in one array)
  • Index values for an array starts at 0 and increments by 1
  • Index values can be a constant value, or can be the result of an arithmetic expression
  • Data in an array do not have to be at consecutive indexes
    • It’s possible to create an array with data at indexes 0, 3, 5, 8. Then if you access the array at index 1 or 2, you will get a null value
  • There are 2 ways to create an array and assign values to the array
    • First way:
      • arrayName=(value1 value2 value3 . . . )
        • value1 will be at index 0, value2 will be at index 1, and so on
        • values are listed with space as delimiter
    • Second way to create the same array:
      • arrayName[0]=value1
      • arrayName[1]=value2
      • arrayName[2]=value3 . . .
      • This way is most often accomplished with a loop
  • For both ways: If the values to be stored in the array contain spaces or other shell metacharacters, quote them to preserve these characters

Accessing Arrays

  • To access one element of an array:

${arrayName[index]}

  • Example

classes=(cis18a cis18b cis18c)

echo ${classes[2]} print cis18c

  • To access all elements of an array:

${arrayName[@]} or ${arrayName[*]}

  • Example

echo ${classes[@]} print cis18a cis18b cis18c

echo ${classes[*]} print cis18a cis18b cis18c

  • Just as with command line arguments, the @ and * are only different when used within double quotes, where “[@]” is the list of individual elements, and “[*]” is a string containing all elements
  • If an array name is used without an index value, it refers to the first element of the array
    • Example: echo $classes print cis18a

Length of an Array

  • To find the number of non-null elements of an array:

${#arrayName[@]}

  • Example

classes=(cis18a cis18b cis18c)

echo ${#classes[@]} print 3

  • To find the number of characters of one element of an array:

${#arrayName[index]}

  • Example

echo ${#classes[2]} print 6



Extract Elements from an Array

  • Just like with filters, when the shell extracts data from an array or an element, it makes a copy and does not modify the array or element
  • To extract some particular elements from an array:

${arrayName[@]:startIndex:num}

where startIndex is the starting index, and num is the number of elements to extract

  • Example

classes=(cis18a cis18b cis18c cis22a cis22b cis22c)

echo ${classes[@]:2:3} print cis18c cis22a cis22b

  • To extract some particular characters of one element of an array:

${arrayName[index]:startChar:num}

where startChar is the starting character, num is the number of characters to extract, and character count starts at 0 for the start character

  • Example

echo ${classes[2]:2:4} print s18c


Adding Elements to an Array

  • To add an element to an array: arrayName[index]=value
    • If index is larger than the last index of the array, then the new value is appended to the array
    • If index is less than or equal to the last index of the array, then the new value replaces an existing value in the array
  • Since the indexes don’t have to be continuous, it’s possible to add an element at an index which is much larger than the last index of the array
  • To append multiple elements to an array

arrayName=( ${arrayName[@]} value1 value2 value3 )

  • Example

classes=(cis18a cis18b)

classes=( ${classes[@]} cis33a cis33b )

echo ${classes[@]} print cis18a cis18b cis33a cis33b

classes[8] = cis18c cis18c is at index 8, values at indexes 4-7 are null


  • To join one array to another array:

array1=( ${array1[@]} ${array2[@]} $array3[@]} )

# array1is now made up of all elements of array1, followed by all elements of array2, then all elements of array3

  • To create a new array from other arrays:

newArray=( ${array1[@]} ${array2[@]} ${array3[@]} )

# newArray is made up of all elements of array1, followed by all elements of array2, then all elements of array3

  • Example

classes=(cis18a cis18b cis18c)

nums=(1 2 3)

classes=( ${classes[@]} ${nums[@]} )

echo ${classes[@]} print cis18a cis18b cis18c 1 2 3


Removing Elements from an Array

  • To null an element of the array:

unset arrayName[index]

  • The value at index is now null, and ${#arrayName[@]} is smaller by 1
  • Example:

classes=(cis18a cis18b cis18c)

unset classes [1]

echo ${classes[1]} print nothing

echo ${#classes[@]} print 2 (size is smaller by 1)

  • To remove an entire array

unset arrayName

Search and Replace Elements in an Array

  • To search and replace an element in the array:

arrayName=( ${arrayName[@]/searchString/replacementString} )

  • Note the pattern is similar to the vi or sed substitute pattern
    • searchString is the what the shell will look for in the array. It can be a regular expression
    • replacementString is what the shell uses to replace the searchString if it’s found in an element of an array
  • Example:

classes=(cis18a cis18b cis18c cis26a )

classes=( ${classes[@]/18/25} )

echo ${classes[@]} print cis25a cis25b cis25c cis26a

Access Each Element in an Array

  • To access each element in the array, use a for in loop
  • Example:

classes=(cis18a cis18b cis18c cis26a cis26b)

for class in ${classes[@]}

do

echo $class print each class in the array

done

Store Multiple Input Data in an Array

  • Use an array to store multiple input data values
  • Example:

files=( `ls` )

for file in ${files[@]}

do

echo $file print each file in the current directory

done

  • Use an array to read multiple data values from the user
  • Use the –a option of read to store input data into an array
  • Example:

read -p “Enter numbers:” -a nums

for num in ${nums[@]}

do

echo $num print each number that user enters

done

  • Use an array to store data from a file
  • Example:

data=( `cat fileA` )

for val in ${data[@]}

do

echo $val print each value in fileA

done

  • Each value in the above example is a whitespace delimited word. So if each line in fileA has 8 words, and there are 5 lines total, then there will be 40 elements in the data array
  • To read a whole line into one element of an array, set the IFS shell variable to \n: IFS=$’\n’
    • IFS is for Input Field Separator – just like with awk

Example:

IFS=$’\n’

lines=( ‘cat fileA’ ) lines is an array with 5 elements

  • If each value of the file can be read in and processed one at a time, without having to keep track of all the values, then it is more efficient not to use an array
  • Alternate way to read data from a file, without using an array:

for val in `cat fileA`

do

echo $val print each value in fileA

done

  • The downside of not using an array is that val is overwritten each time a new value is read in from fileA