如何随机循环bash中的数组(随机播放)

时间:2018-11-09 16:11:24

标签: arrays bash random shuffle

给出一个元素数组(服务器),我该如何对数组进行随机组合以获得一个随机的新数组?

inarray=("serverA" "serverB" "serverC")

outarray=($(randomize_func ${inarray[@]})

echo ${outarray[@]}
serverB serverC serverA

有一个命令shufman page),但并非在每个Linux上都存在。

这是我第一次尝试发布问题自动解答,如果您有更好的解决方案,请发布。

4 个答案:

答案 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)