Simple method to shuffle the elements of an array in BASH shell?

20,472

Solution 1

If you just want to put them into a file (use redirection > )

$ 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

If you want to put the items in array

$ 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;

If your data has &#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;

Solution 2

The accepted answer doesn't match the headline question too well, though the details in the question are a bit ambiguous. The question asks about how to shuffle elements of an array in BASH, and kurumi's answer shows a way to manipulate the contents of a string.

kurumi nonetheless makes good use of the 'shuf' command, while siegeX shows how to work with an array.

Putting the two together yields an actual "simple method to shuffle the elements of an array in BASH shell":

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

Solution 3

From the BashFaq

This function shuffles the elements of an array in-place using the Knuth-Fisher-Yates shuffle algorithm.

#!/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[@]}"

Output

$ ./shuff_ar > somefile.txt
$ cat somefile.txt
b;c;e;f;d;a;
Share:
20,472

Related videos on Youtube

Dave
Author by

Dave

Updated on July 01, 2022

Comments

  • Dave
    Dave over 1 year

    I can do this in PHP but am trying to work within the BASH shell. I need to take an array and then randomly shuffle the contents and dump that to somefile.txt.

    So given array Heresmyarray, of elements a;b;c;d;e;f; it would produce an output file, output.txt, which would contain elements f;c;b;a;e;d;

    The elements need to retain the semicolon delimiter. I've seen a number of bash shell array operations but nothing that seems even close to this simple concept. Thanks for any help or suggestions!

  • Dave
    Dave over 12 years
    I'm trying to use it but getting syntax errors. How do I call the function? I'd like to set "Array2" equal to the new shuffled value so that I have the original as Array1 and the new one as Array2. Also, does the hash have to be removed there in the "size=${}" section?
  • Dave
    Dave over 12 years
    two questions: what is the output? I don't see this in an array...also, will the sed section work for something like "&#abcde;"? Edit: Scratch that. It looks like this can just be directed into a file. Awesome. :-)
  • Dave
    Dave over 12 years
    this is almost it -- I need it modified slightly so that it works, ideally, on values that could be longer...primarily things like "𒍅" or "ꯍ" The key thing is that the length of the element may vary -- it could have as few as 6 chars before the semicolon or as many as 8. When I run the above on a sample test it ends up with a lot of vals like &#x&#xષ which means something's going wrong somewhere.
  • kurumi
    kurumi over 12 years
    what are the sample strings you tested?
  • Dave
    Dave over 12 years
    I think you were writing while I was writing -- the last sample above was magic...works perfectly. I wish I knew more about sed -- seems like such an incredibly useful tool! Thanks so much!
  • SiegeX
    SiegeX over 12 years
    @Dave updated again to reflect your original array contents and output to a file. Pure Bash will have much more performance than calling many external binaries in a pipeline
  • Dave
    Dave over 12 years
    Okay! This makes a lot more sense now and I'm sure you're right about the performance issues -- though in my case, we're not talking enormous files. Thanks very much. I was somehow trying to use "shuffle" like one would in Javascript -- passing it an array. But seeing it used in this context makes sense! Thank you!
  • SiegeX
    SiegeX over 12 years
    @Dave: yes it does, good catch. I removed it. Also RE: performance, never too late to start practicing good techniques. Also, when you come back to this code one day, you're less likely to say WTF is this code doing? vs the alternatives =)
  • deanresin
    deanresin about 5 years
    I had the exact same question as stated in this thread and this answer worked and was the most concise.
  • deanresin
    deanresin about 5 years
    The shuf command uses spaces as a delimiter so will break up any array elements that have spaces in them.

Related