Arrays 如何在bash中随机循环数组(洗牌)
给定一个元素数组(服务器),如何洗牌该数组以获得一个随机的新数组Arrays 如何在bash中随机循环数组(洗牌),arrays,bash,random,shuffle,Arrays,Bash,Random,Shuffle,给定一个元素数组(服务器),如何洗牌该数组以获得一个随机的新数组 inarray=("serverA" "serverB" "serverC") outarray=($(randomize_func ${inarray[@]}) echo ${outarray[@]} serverB serverC serverA 有一个命令shuf(),但它并不存在于每个linux上 这是我第一次尝试发布自我回答的问题stackoverflow,如果您有更好的解决方案,请发布。这是我找到的解决方案(它甚
inarray=("serverA" "serverB" "serverC")
outarray=($(randomize_func ${inarray[@]})
echo ${outarray[@]}
serverB serverC serverA
有一个命令shuf
(),但它并不存在于每个linux上
这是我第一次尝试发布自我回答的问题stackoverflow,如果您有更好的解决方案,请发布。这是我找到的解决方案(它甚至在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"
它完全有可能被优化。sort实用程序能够随机洗牌列表 请尝试以下方法:
servers="serverA serverB serverC serverD"
for s in $servers ; do echo $s ; done | sort -R
您应该使用
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)
inarray=(“服务器A”“服务器B”“服务器C”)
readarray-d“”outarray<这是另一个纯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
它是干净的,并用Bash3和Bash4进行了测试
调用者从outarray
获取结果,而不是将结果放入outarray
,因为outarray=($(perm…)
在要洗牌的任何项包含空格字符时不起作用,如果项包含glob元字符,它也可能会中断。没有很好的方法从Bash函数返回非平凡值
如果从另一个函数调用perm
,则在调用者中声明outarray
(例如使用local-outarray
)将避免创建(或删除)全局变量
无条件交换可以安全地简化代码,代价是对项目本身进行一些无意义的交换。inarray
和outarray都不是数组。这两种赋值在语法上都是无效的。对不起,伪代码,我编辑了我的问题我质疑是否需要在脚本中对数组进行洗牌,而该脚本不能用其他语言编写。相信我,这里的真实用例:)谢谢你的回答,我的sort版本(GNU CoreUtils 5.97)没有-R选项,该选项是在2005年添加的:O,我使用您的答案来证明sort-R不是真正的随机排列:基于散列,它将相同的值组合在一起(如[you should make all variableslocal
中所述,或者将它们泄漏到全局范围。@chepner您在items assignment中引用了$@
,这样可以传递所有参数:“arg1”“arg2”…
改为“arg1 arg2…”
。不确定什么是最好的。如果要像(“foo-bar”“1 2 3”)那样洗牌数组,则必须使用引号
。它保留元素中的空格,而不会将其与分隔元素的空格混淆。@BenjaminW。谢谢您的评论,变量localized@chepner非常感谢!我推荐第一个使用set-f
。请注意,如果我没有弄错的话,第二个使用bash
4.4或更高版本。您可以也可能会加入一个解决方案,其中包含一个简单的,而对于其他版本,
read
组合:)