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.