This might work for you, if you want a genuine pure bash solution.
takeNrandom() {
# This function takes n+1 parameters: k a1 a2 ... an
# Where k in 0..n
# This function sets the global variable _takeNrandom_out as an array that
# consists of k elements chosen at random among a1 a2 ... an with no repetition
local k=$1 i
_takeNrandom_out=()
shift
while((k-->0 && $#)); do
((i=RANDOM%$#+1))
_takeNrandom_out+=( "${!i}" )
set -- "${@:1:i-1}" "${@:i+1}"
done
}
Try it:
$ array=( $'a field with\na newline' 'a second field' 'and a third one' 42 )
$ takeNrandom 2 "${array[@]}"
$ declare -p _takeNrandom_out
declare -a _takeNrandom_out='([0]="a second field" [1]="a field with
a newline" [2]="and a third one")'
(the newline is really preserved in the array field).
This uses positional parameters, and uses set -- "${@:1:i-1}" "${@:i+1}"
to remove the i
-th positional parameter. We also used indirect expansion in the line _takeNrandom_out+=( "${!i}" )
to have access to the i
-th positional parameter.
Note. This uses the RANDOM
variable with a modulo, so the distribution is not exactly uniform. It should be fine for arrays with a small number of fields. Anyway if you have a huge array, you probably shouldn't be using Bash in the first place!