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
- arrayName=(value1 value2 value3 . . . )
- 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
- First way:
- 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