给出一个元素数组(服务器),我该如何对数组进行随机组合以获得一个随机的新数组?
inarray=("serverA" "serverB" "serverC")
outarray=($(randomize_func ${inarray[@]})
echo ${outarray[@]}
serverB serverC serverA
有一个命令shuf
(man page),但并非在每个Linux上都存在。
这是我第一次尝试发布问题自动解答,如果您有更好的解决方案,请发布。
答案 0 :(得分:2)
这是另一个纯Bash解决方案:
#! /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
Shellcheck干净,并经过Bash 3和Bash 4测试。
呼叫者从 outarray
获取结果,而不是将它们放入 outarray
,因为outarray=( $(perm ...) )
不起作用要改组的项目中包含空格字符,如果项目包含全局元字符,它也可能会中断。没有很好的方法从Bash函数返回非平凡的值。
如果从另一个函数调用perm
,则在调用方中声明outarray
(例如,使用local -a outarray
)将避免创建(或破坏)全局变量。
可以无条件地进行交换,从而安全地简化代码,但代价是与它们自身进行一些无意义的交换。
答案 1 :(得分:1)
这是我找到的解决方案(甚至可以在bash <4.0中使用。)
通过下面的评论对Shell进行了检查和编辑。
#!/bin/bash
# random permutation of input
perm() {
# make the input an array
local -a items=( "$@" )
# all the indices of the array
local -a items_arr=( "${!items[@]}" )
# create out array
local -a items_out=()
# loop while there is at least one index
while [ ${#items_arr[@]} -gt 0 ]; do
# pick a random number between 1 and the length of the indices array
local rand=$(( RANDOM % ${#items_arr[@]} ))
# get the item index from the array of indices
local items_idx=${items_arr[$rand]}
# append that item to the out array
items_out+=("${items[$items_idx]}")
### NOTE array is not reindexed when pop'ing, so we redo an array of
### index at each iteration
# pop the item
unset "items[$items_idx]"
# recreate the array
items_arr=( "${!items[@]}" )
done
echo "${items_out[@]}"
}
perm "server1" "server2" "server3" "server4" "server4" "server5" "server6" "server7" "server8"
最有可能对其进行优化。
答案 2 :(得分:0)
sort
实用程序可以随机地整理列表。
尝试以下方法:
servers="serverA serverB serverC serverD"
for s in $servers ; do echo $s ; done | sort -R
答案 3 :(得分:-1)
您应该使用shuf
:
inarray=("serverA" "serverB" "serverC")
IFS=$'\n' outarray=($(printf "%s$IFS" "${inarray[@]}" | shuf))
或者在将数组成员与换行符和其他奇怪字符一起使用时,请使用空的定界字符串:
inarray=("serverA" "serverB" "serverC")
readarray -d '' outarray < <(printf "%s\0" "${inarray[@]}" | shuf -z)