BASH_ARRAYS
# THIS IS AN EXAMPLE OF HOW WE CAN HANDLE MULTIPLE INPUT FILES
# THIS WAY THE INPUTS ARE STORED IN AN ARRAY
# TWO FLAGS ARE USED TO SIGNIFY INPUT FROM OUTPUT -I / -O
declare inputFiles
declare outputFile
#[[ $_ == $0 ]] && getFriendlyFileSize $1 $2
# NEEDS BETTER DOCUMENTATION
# ITERATE OVER ARGUMENT LIST - $#
while (($#)); do
# IF THE FIRST ELEMENT YOU FIND IS -O
if [[ $1 = -o ]]; then
# STORE THE NEXT IN THE OUTPUT FILE AND SHIFT THEM BY ONE
outputFile=$2; shift
# IF ITS -I
elif [[ $1 = -i ]]; then
# APPEND THE SECOND VALUE TO THE ARRAY AND SHIFT THEM BY ONE
inputFiles+=( "$2" ); shift
else
# ALWAYS APPEND THE VALUE TO ARRAY
inputFiles+=( "$1" )
fi
shift
done
################################################
echo "Processing ...."
echo "The following files will be processed: "
# ADD TO GISTBOX - HOW TO PRINT ENTIRE ARRAY
echo "${inputFiles[@]}"; echo
# ADD TO GISTBOX - HOW TO ITERATE OVER ARRAY
for inputFile in "${inputFiles[@]}"; do
echo "Blueprinting File : $inputFile"
if [[ -e $inputFile ]]; then
echo "Input File : $inputFile exists"
else
echo "Input File : $inputFile does not exist"
fi
if [[ -d $inputFile ]]; then
echo "Input File : $inputFile is a directory"
continue
else
echo "Input File : $inputFile is regular, proceeding.."
fi
echo ""
#stat "$inputFile" >> $outputFile
#getFriendlyFileSize 100
process $inputFile >> $outputFile
done
#Declare and an array called array and assign three values:
array=( one two three )
#More examples:
files=( "/etc/passwd" "/etc/group" "/etc/hosts" )
limits=( 10, 20, 26, 39, 48)
To print an array use:
printf "%s\n" "${array[@]}"
printf "%s\n" "${files[@]}"
printf "%s\n" "${limits[@]}"
function duplicates(){
# Declare several variables and counters
declare -A count # associative array
declare line
declare substr
declare FILE_IN=$1
declare line_counter
declare FILE_OT="$1.cnt.dupl.txt"
# iterate over each line of the input.
# accumulate the number of times we've seen this line.
#
# the construct "IFS= read -r line" ensures we capture the line exactly.
while IFS= read -r line; do
(( line_counter++ ))
if [ -z "$line" ]
then
line="BLANKLINE"
fi
(( count["$line"]++ ))
done<$FILE_IN
# add up the number of lines who's count is only 1.
num=0
for c in "${count[@]}"; do
(( key_counter++ ))
if (( $c == 1 )); then
(( num++ ))
fi
done
non_unique_lines=$(($line_counter-$num))
echo "Total lines are : $line_counter"
echo "Unique lines are : $num"
echo "Total keys are : $key_counter"
echo "Non unique lines are : $non_unique_lines"
echo
#The keys are accessed using an exclamation point: ${!array[@]}, the values are accessed using ${array[@]}.
#
# Iterate over hash keys
# for i in ${!array[@]}
# keys = $i
# values = ${array[$i]}
#
# Iterate over hash values
# for i in ${array[@]}
# values = $i
#
# Cleanup previous report
rm $FILE_OT
echo "Report on Multiples per key:" >> $FILE_OT
echo >> $FILE_OT
echo "Multiples : Key" >> $FILE_OT
echo >> $FILE_OT
for i in "${!count[@]}"
do
echo "${count[$i]} : $i" >> $FILE_OT
# echo "key: $i - "
# echo "value: ${count[$i]}"
done
}
# Way to read string into array
IFS=', ' read -r -a array <<< "$string"
# Print entire array
echo "${array[0]}"
# Iterate over array elements
for element in "${array[@]}"
do
echo "$element"
done
# Iterate get both index and value
for index in "${!array[@]}"
do
echo "$index ${array[index]}"
done
##
#The last example is useful because Bash arrays are sparse. In other words,
#you can delete an element or add an element and then the indices are not contiguous.
#
unset "array[1]"
array[42]=Earth
# Get number of elements
# To get the number of elements in an array:
echo "${#array[@]}"
# Get last element of array
#As mentioned above, arrays can be sparse so you shouldn't use the length to get the last element. Here's how you can in Bash 4.2 and later:
echo "${array[-1]}"
#in any version of Bash (from somewhere after 2.05b):
#
echo "${array[@]: -1:1}"
#
#Larger negative offsets select farther from the end of the array. Note the space before the minus sign in the older form. It is required.
# Second way without setting string
string="1:2:3:4:5"
set -f # avoid globbing (expansion of *).
array=(${string//:/ })
for i in "${!array[@]}"
do
echo "$i=>${array[i]}"
done
string="1,2,3,4"
array=(`echo $string | sed 's/,/\n/g'`)
echo ${array[0]}
str="a, b, c, d" # assuming there is a space after ',' as in Q
arr=(${str//,/}) # delete all occurrences of ','
#There's nothing too surprising about associative arrays in bash, they are as you probably expect:
declare -A aa
aa[hello]=world
aa[ab]=cd
#The -A option declares aa to be an associative array. Assignments are then made by putting the "key"
#inside the square brackets rather than an array index. You can also assign multiple items at once:
declare -A aa
aa=([hello]=world [ab]=cd)
#Retrieving values is also as expected:
if [[ ${aa[hello]} == world ]]; then
echo equal
fi
bb=${aa[hello]}
#You can also use keys that contain spaces or other "strange" characters:
aa["hello world"]="from bash"
# Sample basic hash ops
declare -A MYMAP # Create an associative array
MYMAP[foo]=bar # Put a value into an associative array
echo ${MYMAP[foo]} # Get a value out of an associative array
# Creating associative arrays
#Creating
declare -A MYMAP # Explicitly declare
MYMAP[foo]=bar # Or this line implicitly makes it an associative array (in global scope, bash 4.2+ only)
MYMAP[baz]=quux # Can add multiple values one by one
MYMAP[corge]=grault
declare -A MYMAP=( [foo]=bar [baz]=quux [corge]=grault ) # Initialise all at once
echo ${MYMAP[foo]}
echo ${MYMAP[baz]}
declare -A MYMAP # Or declare separately
MYMAP=( [foo]=bar [baz]=quux [corge]=grault ) # Then initialise
echo ${MYMAP[foo]}
echo ${MYMAP[baz]}
#######################################
#Variables as keys
K=baz
MYMAP[$K]=quux # Use a variable as key to put a value into an associative array
echo ${MYMAP[$K]} # Use a variable as key to extract a value from an associative array
echo ${MYMAP[baz]} # Obviously the value is accessible via the literal key
########################################
#Quoting keys
declare -A MYMAP
MYMAP[foo A]="bar B" # Quoting keys makes no difference
MYMAP["corge X"]="grault Y" # Quoting keys makes no difference
echo ${MYMAP["corge X"]} # You can access by quoting
# STDOUT: grault Y
echo ${MYMAP[corge X]} # Or not bother
# STDOUT: grault Y
echo ${MYMAP[foo A]}
# STDOUT: bar B
MYMAP['waldo 1']="fred 2" # Single quotes also make no difference
echo ${MYMAP['waldo 1']}
#STDOUT: fred 2
echo ${MYMAP[waldo 1]}
#STDOUT: fred 2
K=plugh
MYMAP['$K']=xyzzy # Except single quotes prevent variable expansion, as usual
echo ${MYMAP[plugh]}
echo ${MYMAP['$K']}
#STDOUT: xyzzy
###################################################################
# Missing keys
MYMAP[foo]=bar
echo ${MYMAP[missing]} # Accessing a missing value gives ""
# Testing whether a value is missing from an associative array
if [ ${MYMAP[foo]+_} ]; then echo "Found"; else echo "Not found"; fi
#STDOUT: Found
$ if [ ${MYMAP[missing]+_} ]; then echo "Found"; else echo "Not found"; fi
#STDOUT: FoundNot found
###################################################################
#Looping
declare -A MYMAP=( [foo a]=bar [baz b]=quux )
echo "${!MYMAP[@]}" # Print all keys - quoted, but quotes removed by echo
#STDOUT: foo a baz b
# Loop through all keys in an associative array
for K in "${!MYMAP[@]}"; do echo $K; done
#STDOUT:foo a
#STDOUT:baz b
# Wrong way to loop over assoc array
$ for K in ${!MYMAP[@]}; do echo $K; done # WRONG
#STDOUT:foo
#STDOUT:a
#STDOUT:baz
#STDOUT:b
$ # Looping through keys and values in an associative array
$ for K in "${!MYMAP[@]}"; do echo $K --- ${MYMAP[$K]}; done
#STDOUT: foo a --- bar
#STDOUT: baz b --- quux
$ # Loop through all values in an associative array
$ for V in "${MYMAP[@]}"; do echo $V; done
#STDOUT: bar
#STDOUT: quux
###########################################################################
# Clearing assoc array
declare -A MYMAP
MYMAP[foo]=bar
echo ${MYMAP[foo]}
#STDOUT: bar
declare -A MYMAP # Re-declaring DOES NOT clear an associative array
echo ${MYMAP[foo]}
#STDOUT: bar
unset MYMAP # You need to unset and re-declare to get a cleared associative array
declare -A MYMAP
echo ${MYMAP[foo]}
#STDOUT:
###########################################################################
# Deleting keys
MYMAP[foo]=bar
echo ${MYMAP[foo]}
#STDOUT: bar
unset ${MYMAP[foo]} # WRONG
echo ${MYMAP[foo]}
#STDOUT: bar
unset MYMAP[foo] # To delete from an associative array, use "unset" with similar syntax to assigning
# BUT see next section if key contains spaces
echo ${MYMAP[foo]}
#STDOUT:
MYMAP[baz]=quux
echo ${MYMAP[baz]}
#STDOUT: quux
K=baz
unset MYMAP[$K] # Can unset using a variable for the key too
# BUT see next section if variable may contain spaces - always better to quote
echo ${MYMAP[baz]}
#STDOUT:
###############################################################################
# Deleting keys containing spaces
declare -A MYMAP
MYMAP[foo Z]=bar
echo ${MYMAP[foo Z]}
#STDOUT: bar
unset MYMAP[foo Z] # WRONG
#STDERR: bash: unset: `MYMAP[foo': not a valid identifier
#bash: unset: `Z]': not a valid identifier
unset MYMAP["foo Z"] # You must quote keys containing spaces when you unset in an associative array
echo ${MYMAP[foo Z]}
MYMAP[foo Z]=bar
unset MYMAP['foo Z'] # Single quotes work too
echo ${MYMAP[foo Z]}
MYMAP[baz A]=quux
echo ${MYMAP[baz A]}
#STDOUT: quux
K="baz A"
unset MYMAP[$K] # WRONG
#STDERR: bash: unset: `MYMAP[baz': not a valid identifier
#STDERR: bash: unset: `A]': not a valid identifier
unset MYMAP["$K"] # You must quote variables whose values may contain spaces when you unset in an associative array
echo ${MYMAP[baz A]}
MYMAP[baz A]=quux
unset MYMAP['$K'] # Curiously, single quotes work here too, although I'd suggest avoiding them
echo ${MYMAP[baz A]}
################################################################################
#Length
declare -A MYMAP=( [foo a]=bar [baz b]=quux )
echo ${#MYMAP[@]} # Number of keys in an associative array
#STDOUT: 2
echo $#MYMAP[@] # WRONG
#STDOUT: 0MYMAP[@]
echo ${#MYMAP} # WRONG
#STDOUT: 0
################################################################################
# Numeric indexing
declare -A MYMAP=( [foo a]=bar [baz b]=quux )
KEYS=(${!MYMAP[@]}) # Make a normal array containing all the keys in the associative array
echo ${KEYS[0]} # Find a key via an index
#STDOUT: foo a
$ echo ${MYMAP[${KEYS[0]}]} # Find a value via an index
#STDOUT: bar
$ # Loop through using an index
$ for (( I=0; $I < ${#MYMAP[@]}; I+=1 )); do KEY=${KEYS[$I]}; echo $KEY --- ${MYMAP[$KEY]}; done
#STDOUT: foo a --- bar
#STDOUT: baz b --- quux
################################################################################
#Scope
$ unset MYMAP
$ function createmap() { MYMAP[foo]=bar; } # Implicit creation puts it in the global scope
$ echo ${MYMAP[foo]}
$ createmap
$ echo ${MYMAP[foo]}
#STDOUT: bar
$ unset MYMAP
$ function createmaplocal() { declare -A MYMAP; MYMAP[foo]=bar; } # Explicit creation puts it in the local scope
$ echo ${MYMAP[foo]}
$ createmaplocal
$ echo ${MYMAP[foo]}
######################################################################################
#Checking Bash version
$ bash --version # Must be at least version 4 to have associative arrays
GNU bash, version 4.2.24(1)-release (x86_64-pc-linux-gnu)
...
#To declare an array in bash
#Declare and an array called array and assign three values:
array=( one two three )
#More examples:
files=( "/etc/passwd" "/etc/group" "/etc/hosts" )
limits=( 10, 20, 26, 39, 48)
To print an array use:
printf "%s\n" "${array[@]}"
printf "%s\n" "${files[@]}"
printf "%s\n" "${limits[@]}"
#To Iterate Through Array Values
#Use for loop syntax as follows:
for i in "${arrayName[@]}"
do
:
# do whatever on $i
done
#$i will hold each item in an array. Here is a sample working script:
#!/bin/bash
# declare an array called array and define 3 vales
array=( one two three )
for i in "${array[@]}"
do
echo $i
done
################################################################################
#Declaration
#The following explicitly give variables array attributes, making them arrays:
#Syntax Description
ARRAY=() #Declares an indexed array ARRAY and initializes it to be empty. This can also be used to empty an existing array.
ARRAY[0]= #Generally sets the first element of an indexed array. If no array ARRAY existed before, it is created.
declare -a ARRAY #Declares an indexed array ARRAY. An existing array is not initialized.
declare -A ARRAY #Declares an associative array ARRAY. This is the one and only way to create associative arrays.
#Storing values
#Storing values in arrays is quite as simple as storing values in normal variables.
#Syntax Description
ARRAY[N]=VALUE #Sets the element N of the indexed array ARRAY to VALUE. N can be any valid arithmetic expression.
ARRAY[STRING]=VALUE #Sets the element indexed by STRING of the associative array ARRAY.
ARRAY=VALUE #As above. If no index is given, as a default the zeroth element is set to VALUE. Careful, this is even true of associative arrays - there is no error if no key is specified, and the value is assigned to string index "0".
ARRAY=(E1 E2 …) #Compound array assignment - sets the whole array ARRAY to the given list of elements indexed sequentially starting at zero. The array is unset before assignment unless the += operator is used. When the list is empty (ARRAY=()), the array will be set to an empty array. This method obviously does not use explicit indexes. An associative array can not be set like that! Clearing an associative array using ARRAY=() works.
ARRAY=([X]=E1 [Y]=E2 …) #Compound assignment for indexed arrays with index-value pairs declared individually (here for example X and Y). X and Y are arithmetic expressions. This syntax can be combined with the above - elements declared without an explicitly specified index are assigned sequentially starting at either the last element with an explicit index, or zero.
ARRAY=([S1]=E1 [S2]=E2 …) #Individual mass-setting for associative arrays. The named indexes (here: S1 and S2) are strings.
ARRAY+=(E1 E2 …) #Append to ARRAY.
#IMPORTANT: As of now, arrays can't be exported.
#Getting values
#For completeness and details on several parameter expansion variants, see the article about parameter expansion and check the notes about arrays.
#Syntax Description
${ARRAY[N]} #Expands to the value of the index N in the indexed array ARRAY. If N is a negative number,
#it's treated as the offset from the maximum assigned index (can't be used for assignment) - 1
${ARRAY[S]} #Expands to the value of the index S in the associative array ARRAY.
"${ARRAY[@]}"
${ARRAY[@]}
"${ARRAY[*]}"
${ARRAY[*]} #Similar to mass-expanding positional parameters, this expands to all elements. If unquoted, both subscripts * and @
#expand to the same result, if quoted, @ expands to all elements individually quoted, * expands to all elements quoted as a whole.
"${ARRAY[@]:N:M}"
${ARRAY[@]:N:M}
"${ARRAY[*]:N:M}"
${ARRAY[*]:N:M} #Similar to what this syntax does for the characters of a single string when doing substring expansion,
#this expands to M elements starting with element N. This way you can mass-expand individual indexes. The rules for quoting and the subscripts * and @ are the same as above for the other mass-expansions.
#For clarification: When you use the subscripts @ or * for mass-expanding, then the behaviour is exactly what it is for $@ and $* when mass-expanding the positional parameters. You should read this article to understand what's going on.
#Metadata
#Syntax Description
#${#ARRAY[N]} Expands to the length of an individual array member at index N (stringlength)
#${#ARRAY[STRING]} Expands to the length of an individual associative array member at index STRING (stringlength)
#${#ARRAY[@]}
#${#ARRAY[*]} Expands to the number of elements in ARRAY
#${!ARRAY[@]}
#${!ARRAY[*]} Expands to the indexes in ARRAY since BASH 3.0
#Destruction
#The unset builtin command is used to destroy (unset) arrays or individual elements of arrays.
#Syntax Description
unset -v ARRAY
unset -v ARRAY[@]
unset -v ARRAY[*] #Destroys a complete array
unset -v ARRAY[N] #Destroys the array element at index N
unset -v ARRAY[STRING] #Destroys the array element of the associative array at index STRING
string_to_array.bash : Convert string to array
array_iterate.bash : Iterate over array
assoc_array_iter.bash : Iterate over associative array
array_counts.bash : Implement counters in arrays.
declare_print_array.bash : Declare and print entire arrays