Як я можу рандомізувати рядки у файлі за допомогою стандартних інструментів Red Hat Linux?


102

Як я можу рандомізувати рядки у файлі за допомогою стандартних інструментів Red Hat Linux?

У мене немає shufкоманди, тому я шукаю щось на кшталт perlабо awkодного вкладиша, що виконує те саме завдання.


1
Я запитав майже один і той же питання [ stackoverflow.com/questions/286640 / ...
Steve Schnepp


Я вважаю gcc стандартним інструментом у будь-якому Linux. ; D
msb

Відповіді:


64

І один-лайнер Perl ви отримаєте!

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

Він використовує модуль, але модуль є частиною розподілу коду Perl. Якщо це недостатньо добре, ви можете розглянути можливість прокатки власних.

Я спробував використовувати це з -iпрапором ("редагувати на місці"), щоб він зміг редагувати файл. Документація підказує, що вона повинна працювати, але це не так. Він все ще відображає перетасований файл до stdout, але цього разу видаляє оригінал. Я пропоную вам не користуватися цим.

Розглянемо сценарій оболонки:

#!/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), яка сортує цей параметр, не впевнений, коли він з’явився, чи він знаходиться в інших реалізаціях.
Jim T

1
Ця функція була здійснена 10 грудня 2005 року, наступний реліз - 5,94, тому я гадаю, що вона доступна з цієї версії.
Jim T

41
В OS X ви можете встановити gnu coreutils з домашньою мовою: brew install coreutilsУсі утиліти мають префікс ag, так що: gsort --random-sortабо gshufпрацюватимуть як очікувалося
Майк

3
+1 @mike Я використовую Macports, а також у мене був gsortі gshufвстановлений, коли я це робивport install coreutils
Ной Суссман,

10
Це рішення добре, лише якщо у ваших рядках немає повторень. У такому разі всі екземпляри цього рядка з’являться поруч. Подумайте про використання shufнатомість (на Linux).
Алі Дж

118

shuf найкращий спосіб.

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


Це чудово. Схоже, це в ядрах GNU.
ariddell

4
Я підозрюю, що причина sort -Rповільна в тому, що для кожного рядка обчислюється хеш. З Документів: " Сортувати за допомогою хеш-клавіш введення та сортування хеш-значень "
Джо Флін

13
остерігайтеся, shufзавантажує все в пам’ять.
jfs

1
@benroth: З того, що я можу сказати, дійсно великі вхідні показники збільшення пам'яті можуть дещо допомогти , але це все-таки повільно. У моїх тестах сортування 1-мільйонного вхідного файлу, створеного за допомогою, seq -f 'line %.0f' 1000000займало стільки ж, тривалий час (багато, набагато довше, ніж з shuf), незалежно від того, скільки пам'яті я виділив.
mklement0

1
@ mklement0, ти маєш рацію! Я просто спробував це з набагато більшим файлом, ніж у мене раніше, і хеширование, здається, є вузьким місцем.
Бенрот

23
cat yourfile.txt | while IFS= read -r f; do printf "%05d %s\n" "$RANDOM" "$f"; done | sort -n | cut -c7-

Прочитайте файл, додайте кожен рядок зі випадковим числом, сортуйте файл за тими випадковими префіксами, виріжте префікси згодом. Однолінійний, який повинен працювати в будь-якій напівмодерній оболонці.

EDIT: включено зауваження Річарда Хансена.


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
@Richard Hansen: Дякую, ці запропоновані зміни очевидно підходять, я відредагував своє повідомлення.
ChristopheD

9

Однолінійний пітон:

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

Але дивіться цю публікацію щодо недоліків пітона random.shuffle(). Він не буде добре працювати з багатьма (більше 2080) елементами.


5

Пов'язане з відповіддю Джима:

Моє ~/.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- це потрібно, оскільки $_=<>це неявно робилося з усім файлом замість рядків.)


Повторюючи, що сортування -R не існує в OS X, але +1 для великих чудових відповідей Perl, і взагалі чудової відповіді.
Кріс Лутц

Ви можете встановити GNU coreutils на OS X, але (як я це робив у минулому), ви повинні бути обережними, щоб не зламати вбудовані інструменти ... Це, як було сказано, OP є на Redhat Linux, який безумовно має GNU coreutils стандарт.
ефеміент

3

Коли я встановлюю coreutils з домашньою мовою

brew install coreutils

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


варити за допомогою префікса всіх команд з gтак shufстало gshufдля мене.
Йорн

^ Це тому, що вони не POSIX, або я просто повністю відключений?
Дейв Лю


1

FreeBSD має власну випадкову утиліту:

cat $file | random | ...

Це в / usr / games / random, тому якщо ви не встановили ігри, вам не пощастило.

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


-1

На OSX, захоплення останніх з http://ftp.gnu.org/gnu/coreutils/ і щось подібне

./configure зробити sudo make install

... повинен дати вам / usr / local / bin / sort - випадковий сортування

не псуючи / usr / bin / sort


це не спрацювало для мене на OSX (10.7). Я отримав "configure: error: компілятор C не може створити виконувані файли".
Dolan Antenucci

@dolan Перевірте свої дозволи?
Benubird

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.