【问题标题】:Simple method to shuffle the elements of an array in BASH shell?在 BASH shell 中打乱数组元素的简单方法?
【发布时间】:2011-07-28 20:40:10
【问题描述】:

我可以在 PHP 中执行此操作,但我正在尝试在 BASH shell 中工作。我需要获取一个数组,然后随机打乱内容并将其转储到somefile.txt

因此,给定数组 Heresmyarray,包含元素 a;b;c;d;e;f;,它将生成一个输出文件 output.txt,其中包含元素 f;c;b;a;e;d;

元素需要保留分号分隔符。我见过许多 bash shell 数组操作,但似乎没有任何东西接近这个简单的概念。感谢您的任何帮助或建议!

【问题讨论】:

    标签: bash shell shuffle


    【解决方案1】:

    接受的答案与标题问题不太匹配,尽管问题中的细节有点模棱两可。该问题询问如何在 BASH 中打乱数组的元素,kurumi 的回答显示了一种操作字符串内容的方法。

    kurumi 仍然很好地利用了“shuf”命令,而 siegeX 展示了如何使用数组。

    将两者放在一起会产生一个实际的“在 BASH shell 中打乱数组元素的简单方法”:

    $ myarray=( 'a;' 'b;' 'c;' 'd;' 'e;' 'f;' )
    $ myarray=( $(shuf -e "${myarray[@]}") )
    $ printf "%s" "${myarray[@]}"
    d;b;e;a;c;f;
    

    【讨论】:

    • 我的问题与此线程中所述完全相同,并且此答案有效并且最简洁。
    • shuf 命令使用空格作为分隔符,因此将分解任何包含空格的数组元素。
    【解决方案2】:

    来自BashFaq

    此函数使用 Knuth-Fisher-Yates 洗牌算法就地洗牌数组的元素。

    #!/bin/bash
    
    shuffle() {
       local i tmp size max rand
    
       # $RANDOM % (i+1) is biased because of the limited range of $RANDOM
       # Compensate by using a range which is a multiple of the array size.
       size=${#array[*]}
       max=$(( 32768 / size * size ))
    
       for ((i=size-1; i>0; i--)); do
          while (( (rand=$RANDOM) >= max )); do :; done
          rand=$(( rand % (i+1) ))
          tmp=${array[i]} array[i]=${array[rand]} array[rand]=$tmp
       done
    }
    
    # Define the array named 'array'
    array=( 'a;' 'b;' 'c;' 'd;' 'e;' 'f;' )
    
    shuffle
    printf "%s" "${array[@]}"
    

    输出

    $ ./shuff_ar > somefile.txt
    $ cat somefile.txt
    b;c;e;f;d;a;
    

    【讨论】:

    • 我正在尝试使用它,但遇到语法错误。如何调用该函数?我想将“Array2”设置为新的洗牌值,以便将原始值设置为 Array1,将新值设置为 Array2。此外,是否必须在“size=${}”部分中删除哈希?
    • @Dave 再次更新以反映您的原始数组内容并输出到文件。 Pure Bash 将比在管道中调用许多外部二进制文件具有更高的性能
    • 好的!现在这更有意义了,我相信您对性能问题的看法是正确的——尽管就我而言,我们并不是在谈论巨大的文件。非常感谢。我以某种方式尝试像在 Javascript 中那样使用“shuffle”——将它传递给一个数组。但是在这种情况下使用它是有道理的!谢谢!
    • @Dave:是的,很好。我删除了它。还有RE:表演,开始练习好的技巧永远不会太晚。此外,当你有一天回到这段代码时,你不太可能说 WTF 这段代码在做什么? 与替代方案相比 =)
    【解决方案3】:

    如果您只想将它​​们放入文件中(使用重定向>)

    $ echo "a;b;c;d;e;f;" | sed -r 's/(.[^;]*;)/ \1 /g' | tr " " "\n" | shuf | tr -d "\n"
      d;a;e;f;b;c;
    
    $ echo "a;b;c;d;e;f;" | sed -r 's/(.[^;]*;)/ \1 /g' | tr " " "\n" | shuf | tr -d "\n" > output.txt
    

    如果要将项目放入数组中

    $ array=( $(echo "a;b;c;d;e;f;" | sed -r 's/(.[^;]*;)/ \1 /g' | tr " " "\n" | shuf | tr -d " " ) )
    $ echo ${array[0]}
    e;
    $ echo ${array[1]}
    d;
    $ echo ${array[2]}
    a;
    

    如果你的数据有&#abcde;

    $ echo "a;&#abcde;c;d;e;f;" | sed -r 's/(.[^;]*;)/ \1 /g' | tr " " "\n" | shuf | tr -d "\n"
    d;c;f;&#abcde;e;a;
    $ echo "a;&#abcde;c;d;e;f;" | sed -r 's/(.[^;]*;)/ \1 /g' | tr " " "\n" | shuf | tr -d "\n"
    &#abcde;f;a;c;d;e;
    

    【讨论】:

    • 两个问题:输出是什么?我没有在数组中看到这个......另外,sed 部分是否适用于“abcde;”之类的东西?编辑:从头开始。看起来这可以直接放入文件中。惊人的。 :-)
    • 差不多了——我需要稍微修改一下,以便它在理想情况下适用于可能更长的值......主要是像“𒍅”这样的东西或“ꯍ”关键是元素的长度可能会有所不同——分号前可能少至 6 个字符或多至 8 个字符。当我在示例测试中运行上述内容时,它最终会出现很多类似 & #xષ这意味着某处出了点问题。
    • 您测试的示例字符串是什么?
    • 我想你是在我写作的时候写作的——上面的最后一个示例很神奇……效果很好。我希望我对 sed 有更多的了解——这似乎是一个非常有用的工具!非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 2015-08-04
    • 2021-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    相关资源
    最近更新 更多