Test if a variable is an array:
# is_array - Tests whether variable name is an array
# Parameters:
# name - name of variable to test
# Returns:
# 0 if an array
# 1 otherwise
is_array()
{
# Only takes one argument
if [ "${#}" -ne "1" ]; then
return 1
fi
# Name of the variable to test
local name="$1"; shift
# Run the declare command against the variable
local x=$(declare -p $name 2>/dev/null)
# If it errored then the name probably isn't even
# a variable
if [ "$?" -ne "0" ]; then
return 1
else
# It is at least declared, test if it is an array
if [ "${x:8:2}" == "-a" ]; then
return 0
else
return 1
fi
fi
}
Push values onto an array:# array_push - Pushes one or more values onto an array
# Parameters:
# name - name of the destination array
# ... - values to push onto array
# Returns:
# Nothing
array_push()
{
# Need two or more arguments
if [ "${#}" -lt "2" ]; then
return
fi
# Name of the destination array
local name="$1"; shift
# Number of elements we're going to push
local numElements=${#}
# Counter
local i=0
# Starting position of destination array is the
# size of the array
eval local start=\$\{\#$name\[\@\]\}
# Iterate over the elements supplied, adding them
# to the destination array
while [ "$i" -lt "$numElements" ]; do
pos=$((start+i))
eval $name\[$pos\]=\"$1\";
shift
((i++))
done
}
Pop from an array:# array_pop - pops a value from the end of the array
# Parameters:
# name - name of array
# dest - optional name of variable to put value in
# Returns:
# Nothing
array_pop()
{
# Need at least one argument
if [ "${#}" -eq "0" ]; then
return
fi
# Name of the array
local name="$1"; shift
# If we have a second argument, use it to write value
if [ -n "$1" ]; then
local dest="$1"; shift
else
local dest=""
fi
# Size of the array
eval local numElements=\$\{\#$name\[\@\]\}
# Index of element is one less than size
local index=$((numElements-1))
# Get the value
eval local value=\"\$\{$name\[$index\]\}\"
if [ -n "$dest" ]; then
# Update the specified dest variable
eval $dest=\"$value\"
else
# Simply echo the value
echo "$value"
fi
# Unset from the array
eval unset $name\[$index\]
}
One thing to note is the clash between variable names. E.g. if you wanted to return the value into the name variable, it would be bad to call that variable 'value'. local doesn't help here, best option would probably to use obscure variable names that are unlikely to clash.Walk an array:
# array_walk - Walks through an array, calling the
# callback function for each element
# Parameters:
# name - name of array to walk
# callback - name of callback function
# ... - any parameters to be passed to callback
# Returns:
# Nothing
array_walk()
{
# Name of array to walk over
local name="$1"; shift
# Name of call back function
local callback="$1"; shift
# TODO - We should probably check whether callback
# is actually a function
# Number of elements in array
eval local numElements=\$\{\#$name\[\@\]\}
# Counter
local i=0
# Iterate over the elements in the array
while [ "$i" -lt "$numElements" ]; do
# Get the value
eval value=$\{$name\[$i\]\}
# Check whether it is an array
is_array $value
if [ "$?" -eq "0" ]; then
# If so, recursively walk that array
array_walk "$value" "$callback" "$@"
else
# Just a variable, so call the callback
# function giving it the args and value
$callback "$@" "$value"
fi
((i++))
done
}
Now, a little play with those functions:declare -a aTest
echo First push
array_push aTest 'Hello' 'there' 'you' ':)'
echo new array is ${aTest[@]}
echo
declare -a aTest2
echo Second push
array_push aTest2 'How' 'are' 'you today?'
echo second array is ${aTest2[@]}
echo
echo Third push to add second array to the first
array_push aTest 'aTest2'
echo first array is ${aTest[@]}
echo
echo Defining destination array
declare -a aMerged
echo defining callback function
merge()
{
local name="$1"
local value="$2"
# Simple push the value onto the destination
array_push "$name" "$value"
}
echo Doing walk
array_walk aTest merge aMerged
echo merged array is ${aMerged[@]}
echo
echo Popping last element of merged array by reference
array_pop aMerged val
echo Value is $val
echo and again
array_pop aMerged val
echo Value is $val
echo merged array is now ${aMerged[@]}
Running it gives us:$ ./arrays2.sh First push new array is Hello there you :) Second push second array is How are you today? Third push to add second array to the first first array is Hello there you :) aTest2 Defining destination array defining callback function Doing walk merged array is Hello there you :) How are you today? Popping last element of merged array by reference Value is you today? and again Value is are merged array is now Hello there you :) How $So that sort of works. Next I should add an array_indexes() and array_values(). Oh, and happy new year :D
Edit:
Added array_pop function.
Nooo is_array returning 0 for true and 1 for false! Bloody sysadmin programmers /rollseyes
ReplyDeleteOh and happy new year from NZ :)
ReplyDeleteHah :) Happy new year to you too! And yeah, sorry about the whole 0/1 thing :D
ReplyDeletehe is actually correct with the 0/1 thing as 0 is defined as true in shell, everything else is false
ReplyDeleteYeah, that's just JC being a developer :)
ReplyDeletePretty good post. I just stumbled upon your blog and wanted to say that I have really enjoyed reading your blog posts. Any way I'll be subscribing to your feed and I hope you post again soon. Big thanks for the useful info. camping mit kind und hund
ReplyDeleteHow the government can help casino investors keep on edge over
ReplyDeleteThe government 메이저사이트 목록 wants to 배구 토토 넷마블 set up หารายได้เสริม a “safe” casino industry and create “a safe and secure future for online 사설토토 운영자 처벌 유니88 Read more in 온라인 바카라 our guide.