Given an array of elements (servers), how do I shuffle the array to obtain a random new array ?
inarray=("serverA" "serverB" "serverC")
outarray=($(randomize_func ${inarray[@]})
echo ${outarray[@]}
serverB serverC serverA
There is a command shuf (man page) but it does not exist on every linux.
This is my first attempt to post a self-answered question stackoverflow, if you have a better solution, please post it.
This is another pure Bash solution:
#! /bin/bash
# Randomly permute the arguments and put them in array 'outarray'
function perm
{
outarray=( "$@" )
# The algorithm used is the Fisher-Yates Shuffle
# (https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle),
# also known as the Knuth Shuffle.
# Loop down through 'outarray', swapping the item at the current index
# with a random item chosen from the array up to (and including) that
# index
local idx rand_idx tmp
for ((idx=$#-1; idx>0 ; idx--)) ; do
rand_idx=$(( RANDOM % (idx+1) ))
# Swap if the randomly chosen item is not the current item
if (( rand_idx != idx )) ; then
tmp=${outarray[idx]}
outarray[idx]=${outarray[rand_idx]}
outarray[rand_idx]=$tmp
fi
done
}
inarray=( 'server A' 'server B' 'server C' )
# Declare 'outarray' for use by 'perm'
declare -a outarray
perm "${inarray[@]}"
# Display the contents of 'outarray'
declare -p outarray
It's Shellcheck-clean, and tested with Bash 3 and Bash 4.
The caller gets the results from outarray rather than putting them in outarray because outarray=( $(perm ...) ) doesn't work if any of the items to be shuffled contain whitespace characters, and it may also break if items contain glob metacharacters. There is no nice way to return non-trivial values from Bash functions.
If perm is called from another function then declaring outarray in the caller (e.g. with local -a outarray) will avoid creating (or clobbering) a global variable.
The code could safely be simplified by doing the swap unconditionally, at the cost of doing some pointless swaps of items with themselves.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With