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 variables
local
中所述,或者将它们泄漏到全局范围。@chepner您在items assignment中引用了
$@
,这样可以传递所有参数:
“arg1”“arg2”…
改为
“arg1 arg2…”
。不确定什么是最好的。如果要像
(“foo-bar”“1 2 3”)那样洗牌数组,则必须使用引号
。它保留元素中的空格,而不会将其与分隔元素的空格混淆。@BenjaminW。谢谢您的评论,变量localized@chepner非常感谢!我推荐第一个使用
set-f
。请注意,如果我没有弄错的话,第二个使用
bash
4.4或更高版本。您可以也可能会加入一个解决方案,其中包含一个简单的
,而对于其他版本,
read
组合:)