Как я могу рандомизировать строки в файле с помощью стандартных инструментов Red Hat Linux?

102

Как я могу рандомизировать строки в файле с помощью стандартных инструментов Red Hat Linux?

У меня нет shufкоманды, так что я ищу что - то вроде perlили awkоднострочника что совершающего ту же задачу.

Стюарт Вудворд
источник
1
Я задал почти тот же вопрос [ stackoverflow.com/questions/286640/…
Стив Шнепп
Я считаю gcc стандартным инструментом в любом Linux. ; D
msb

Ответы:

64

И вы получите однострочник Perl!

perl -MList::Util -e 'print List::Util::shuffle <>'

Он использует модуль, но он является частью дистрибутива кода Perl. Если этого недостаточно, вы можете попробовать прокатить свой собственный.

Я пробовал использовать это с -iфлагом («редактировать на месте»), чтобы он редактировал файл. Документация предполагает, что это должно работать, но это не так. Он по-прежнему отображает перетасованный файл в стандартный вывод, но на этот раз удаляет оригинал. Я предлагаю вам не использовать его.

Рассмотрим сценарий оболочки:

#!/bin/sh

if [[ $# -eq 0 ]]
then
  echo "Usage: $0 [file ...]"
  exit 1
fi

for i in "$@"
do
  perl -MList::Util -e 'print List::Util::shuffle <>' $i > $i.new
  if [[ `wc -c $i` -eq `wc -c $i.new` ]]
  then
    mv $i.new $i
  else
    echo "Error for file $i!"
  fi
done

Не проверено, но, надеюсь, работает.

Крис Лутц
источник
Чтобы сделать резервную копию исходного файла, вы можете добавить
Стив Шнепп,
Я обычно не поклонник Perl, но наткнулся на этот рубинового пример , который имеет преимущество быть короче: ruby -e 'puts STDIN.readlines.shuffle'. Потребуется тестирование на больших входах, чтобы увидеть, сопоставима ли скорость. (также работает на OS X)
mivk
на комментарий ниже, shufзагружает все в память, поэтому он не работает с действительно огромным файлом (у меня ~ 300 ГБ tsv). Этот сценарий perl не удался и у меня, но без ошибок, кроме Killed. Есть идеи, загружает ли решение Perl все в память или есть какая-то другая проблема, с которой я сталкиваюсь?
seth127
211

Хм, давай не забываем

sort --random-sort
Джим Т
источник
1
Ну, я использую gnu-coreutils 7.1 (стандартная установка gentoo), в котором есть сортировка с этой опцией, не знаю, когда она появилась, или есть ли она в других реализациях.
Джим Т.
1
Эта функция была реализована 10 декабря 2005 г., следующим за ней был выпуск 5.94, так что я предполагаю, что она доступна с этой версии.
Джим Т.
41
В OS X вы можете установить gnu coreutils с помощью homebrew: brew install coreutilsвсе утилиты имеют префикс ag, поэтому: gsort --random-sortили gshufбудут работать должным образом,
Майк
3
+1 @mike. Я использую Macports, и у меня тоже было gsortи gshufустановлено, когда я это делалport install coreutils
Ной Сассман
10
Это решение подходит только в том случае, если в ваших строках нет повторов. Если они это сделают, все экземпляры этой строки появятся рядом друг с другом. Рассмотрите возможность использования shufвместо этого (в Linux).
Али Джей
119

shuf это лучший способ.

sort -Rмучительно медленно. Я просто пробовал отсортировать файл размером 5ГБ. Я сдался через 2,5 часа. Потом shufразобрал за минуту.

Михал Ильич
источник
Это круто. Похоже, он находится в GNU coreutils.
ariddell
4
Я подозреваю, что причина sort -Rмедленная в том, что вычисляет хэш для каждой строки. Из документации: « Сортировка путем хеширования ключей ввода, а затем сортировки хеш-значений »
Джо Флинн,
14
будьте осторожны, shufзагружает все в память.
jfs
1
@benroth: Насколько я могу судить, при действительно большом количестве входных данных увеличение памяти может несколько помочь , но в целом это все еще медленное. В моих тестах сортировка входного файла длиной в 1 миллион строк, созданного с помощью, seq -f 'line %.0f' 1000000занимала одинаково много времени для обработки (намного, намного дольше, чем с помощью shuf), независимо от того, сколько памяти я выделил.
mklement0
1
@ mklement0, ты прав! Я просто попробовал это с файлом гораздо большего размера, чем был раньше, и хеширование, похоже, действительно является узким местом.
benroth
23
cat yourfile.txt | while IFS= read -r f; do printf "%05d %s\n" "$RANDOM" "$f"; done | sort -n | cut -c7-

Прочтите файл, добавьте к каждой строке случайное число, отсортируйте файл по этим случайным префиксам, затем удалите префиксы. Однострочный, который должен работать в любой полусовременной оболочке.

РЕДАКТИРОВАТЬ: включены замечания Ричарда Хансена.

ChristopheD
источник
1
Это работает и является творческим решением, но удаляет ведущие пробелы в строках.
Крис Лутц,
@Chris, изменив последний фрагмент на | sed 's / ^ [^ \ t] * \ t //', должен это исправить
bdonlan
Престижность простоте подхода!
Шашикант Коре
3
+1 для соответствия POSIX (кроме $RANDOM), но -1 для уничтожения данных. Замена while read fна while IFS= read -r fпредотвратит readудаление начальных и конечных пробелов (см. Этот ответ ) и предотвратит обработку обратных косых черт. Использование случайной строки фиксированной длины предотвратит cutудаление начальных пробелов. Результат: cat yourfile.txt | while IFS= read -r f; do printf "%05d %s\n" "$RANDOM" "$f"; done | sort -n | cut -c7-
Ричард Хансен,
3
@ Ричард Хансен: Спасибо, предлагаемые изменения, очевидно, подходят, я отредактировал свой пост.
ChristopheD
9

Однострочник для Python:

python -c "import random, sys; lines = open(sys.argv[1]).readlines(); random.shuffle(lines); print ''.join(lines)," myFile

А для печати только одной случайной строки:

python -c "import random, sys; print random.choice(open(sys.argv[1]).readlines())," myFile

Но посмотрите этот пост о недостатках python random.shuffle(). Он не будет работать со многими (более 2080) элементами.

скай
источник
5

Связано с ответом Джима:

My ~/.bashrcсодержит следующее:

unsort ()
{
    LC_ALL=C sort -R "$@"
}

С сортировкой GNU coreutils, -R= --random-sort, которая генерирует случайный хэш каждой строки и сортирует по нему. Рандомизированный хеш на самом деле не будет использоваться в некоторых локали в некоторых более старых (глючных) версиях, в результате чего он будет возвращать нормальный отсортированный вывод, поэтому я установил LC_ALL=C.


Относится к ответу Криса:

perl -MList::Util=shuffle -e'print shuffle<>'

является немного более коротким однострочником. ( -Mmodule=a,b,cсокращение от -e 'use module qw(a b c);'.)

Причина, по которой простота -iне работает для перетасовки на месте, заключается в том, что Perl ожидает, что это printпроизойдет в том же цикле, в котором читается файл, и print shuffle <>не выводит данные до тех пор, пока все входные файлы не будут прочитаны и закрыты.

В качестве более короткого обходного пути

perl -MList::Util=shuffle -i -ne'BEGIN{undef$/}print shuffle split/^/m'

перетасует файлы на месте. ( -nозначает «заключить код в while (<>) {...}цикл; BEGIN{undef$/}заставляет Perl работать с файлами по очереди, а не по строкам, и split/^/mнеобходимо, потому что $_=<>это было неявно выполнено с целым файлом, а не со строками.)

эфемерный
источник
Повторяю, что sort -R не существует в OS X, но +1 для некоторых отличных ответов Perl и отличного ответа в целом.
Крис Лутц,
Вы можете установить GNU coreutils на OS X, но (как я делал в прошлом) вы должны быть осторожны, чтобы не сломать встроенные инструменты ... При этом OP находится в Redhat Linux, в котором определенно есть GNU coreutils стандартный.
ephemient
3

Когда я устанавливаю coreutils с помощью homebrew

brew install coreutils

shufстановится доступным как n.

Джон МакДоннелл
источник
brew ставил перед всеми командами префиксы, gтак shufстало gshufдля меня.
Йорн
^ Это потому, что они не POSIX, или я просто не согласен?
Дэйв Лю
1

Mac OS X с DarwinPorts:

sudo port install unsort
cat $file | unsort | ...
Coroos
источник
1

FreeBSD имеет свою собственную случайную утилиту:

cat $file | random | ...

Он находится в / usr / games / random, поэтому, если вы не установили игры, вам не повезло.

Вы можете рассмотреть возможность установки таких портов, как textproc / rand или textproc / msort. Они вполне могут быть доступны в Linux и / или Mac OS X, если переносимость вызывает беспокойство.

Coroos
источник
-1

В OSX скачивание последней версии с http://ftp.gnu.org/gnu/coreutils/ и чего-то вроде

./configure сделать sudo make install

... должен дать вам / usr / local / bin / sort --random-sort

без ошибок / usr / bin / sort

Дэн Брикли
источник
это не сработало для меня в OSX (10.7). Я получил «configure: error: компилятор C не может создавать исполняемые файлы».
Долан Антенуччи
@dolan Проверить разрешения?
Benubird
-1

Или получите его с MacPorts:

$ sudo port install coreutils

и / или

$ /opt/local//libexec/gnubin/sort --random-sort
Чедвик Боггс
источник