Простой способ перетасовать элементы массива в оболочке BASH?

Я могу сделать это на PHP, но пытаюсь работать в оболочке BASH. Мне нужно взять массив, а затем случайным образом перемешать содержимое и сбросить его в somefile.txt.

Таким образом, заданный массив Heresmyarray из элементов a;b;c;d;e;f; создаст выходной файл output.txt, который будет содержать элементы f;c;b;a;e;d;.

Элементы должны сохранять разделитель с запятой. Я видел несколько операций с массивами оболочки bash, но ничего похожего на эту простую концепцию нет. Спасибо за любую помощь или предложения!


person Dave    schedule 04.04.2011    source источник


Ответы (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;
person kurumi    schedule 04.04.2011
comment
два вопроса: что на выходе? Я не вижу этого в массиве... кроме того, будет ли раздел sed работать для чего-то вроде &#abcde;? Изменить: поцарапать это. Похоже, это можно просто направить в файл. Потрясающий. :-) - person Dave; 04.04.2011
comment
это почти все - мне нужно немного изменить его, чтобы в идеале он работал со значениями, которые могут быть длиннее... в первую очередь такие вещи, как ???? или ꯍ. Ключевым моментом является то, что длина элемента может варьироваться - он мог бы иметь всего 6 символов перед точкой с запятой или целых 8. Когда я запускаю приведенное выше в примере теста, он заканчивается множеством vals, таких как &#x&#xષ, что означает, что что-то где-то идет не так. - person Dave; 04.04.2011
comment
какие образцы строк вы тестировали? - person kurumi; 04.04.2011
comment
Я думаю, что вы писали, пока я писал - последний образец выше был волшебным... работает отлично. Хотел бы я знать больше о sed — кажется, это такой невероятно полезный инструмент! Спасибо большое! - person Dave; 04.04.2011

Принятый ответ не слишком хорошо соответствует заголовку вопроса, хотя детали вопроса немного неоднозначны. Вопрос касается того, как перетасовать элементы массива в BASH, и ответ куруми показывает способ управления содержимым строки.

kurumi, тем не менее, хорошо использует команду shuf, а siegeX показывает, как работать с массивом.

Соединив их вместе, мы получаем фактический «простой метод перетасовки элементов массива в оболочке BASH»:

$ myarray=( 'a;' 'b;' 'c;' 'd;' 'e;' 'f;' )
$ myarray=( $(shuf -e "${myarray[@]}") )
$ printf "%s" "${myarray[@]}"
d;b;e;a;c;f;
person David McKinley    schedule 12.02.2017
comment
У меня был тот же вопрос, что и в этой теме, и этот ответ сработал и был самым кратким. - person deanresin; 26.11.2018
comment
Команда shuf использует пробелы в качестве разделителя, поэтому разбивает любые элементы массива, в которых есть пробелы. - person deanresin; 12.12.2018

Из BashFaq

Эта функция перемешивает элементы массива на месте, используя алгоритм перетасовки Кнута-Фишера-Йейтса.

#!/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;
person SiegeX    schedule 04.04.2011
comment
Я пытаюсь использовать его, но получаю синтаксические ошибки. Как мне вызвать функцию? Я хотел бы установить Array2 равным новому перетасованному значению, чтобы у меня был оригинал как Array1, а новый - как Array2. Кроме того, нужно ли удалять хеш в разделе size=${}? - person Dave; 04.04.2011
comment
@Dave снова обновлен, чтобы отразить исходное содержимое массива и вывести его в файл. Чистый Bash будет иметь гораздо большую производительность, чем вызов множества внешних двоичных файлов в конвейере. - person SiegeX; 04.04.2011
comment
Хорошо! Теперь это имеет гораздо больше смысла, и я уверен, что вы правы насчет проблем с производительностью, хотя в моем случае мы не говорим об огромных файлах. Спасибо большое. Я как-то пытался использовать перемешивание, как в Javascript, - передавая ему массив. Но использование его в этом контексте имеет смысл! Благодарю вас! - person Dave; 04.04.2011
comment
@Dave: да, хороший улов. Я удалил его. Также RE: производительность, никогда не поздно начать практиковать хорошие техники. Кроме того, когда вы однажды вернетесь к этому коду, вы с меньшей вероятностью скажете Что делает этот код? по сравнению с альтернативами =) - person SiegeX; 04.04.2011