Виберіть випадкові рядки з файлу


240

У сценарії Bash я хочу виділити N випадкових рядків із вхідного файлу та вивести в інший файл.

Як це можна зробити?


Сортуйте файл випадковим чином і виберіть N перших рядків.
— Piotr Praszmo


31
це не дублікат - він хоче N рядків проти 1 рядка.
— OneSolitaryNoob


1
Я не згоден з тим sort -R, що це робить багато зайвої роботи, особливо для довгих файлів. Ви можете використовувати $RANDOM, % wc -l, jot, sed -n(а - ля stackoverflow.com/a/6022431/563329 ), і функціональні можливості Баш (масиви, команди перенаправлення, і т.д.) , щоб визначити свою власну peekфункцію , яка на самому ділі буде працювати з файлами 5000000 рядки.
— ізоморфізми

Відповіді:


627

Використовуйте shufз -nопцією , як показано нижче, щоб отримати Nвипадкові лінії:

shuf -n N input > output

2
Якщо вам просто потрібен випадковий набір рядків, а не у випадковому порядку, то shuf дуже неефективний (для великого файлу): краще зробити вибірку резервуарів, як у цій відповіді .
— petrelharp

Я запустив це на 500М рядковий файл, щоб отримати 1000 рядків, і це зайняло 13 хв. Доступ до файлу не було місяцями, і він знаходиться на дисководі SSD Amazon EC2.
— Т. Брайан Джонс

так це по суті більш випадково sort -R?
— Мона Джалал

1
@MonaJalal nope просто швидше, оскільки він зовсім не повинен порівнювати лінії.
— rogerdpack

Чи в кінцевому підсумку вона дає один і той же рядок не один раз?
— Фредерік Норд

161

Сортуйте файл випадковим чином та виберіть перші 100рядки:

$ sort -R input | head -n 100 >output

43
sortнасправді впорядковуються однакові лінії разом, тому якщо у вас можуть бути повторювані рядки та у вас встановлений shuf(інструмент gnu), краще використовувати для цього.
— Кевін

22
Андальсо, це, безумовно, змусить вас багато чекати, якщо у вас значно великий файл - 80kk рядків -, тоді як він shuf -nдіє досить миттєво.
— Рубенс

28
сортування -R недоступне під Mac OS X (10.9)
— Mirko Ebert

3
@ tfb785: sort -Rце, мабуть, варіант GNU, встановіть GNU coreutils. btw, shufтакож входить до основних ядер.
— jfs

1
@JFSebastian Код: sort -R input | head -n <num_lines>. Вхідний файл становив 279 ГБ, з 2бі + рядками. Не можу поділитися цим. У будь-якому разі, справа в тому, що ви можете зберігати деякі рядки в пам'яті за допомогою переміщення, щоб зробити випадковий вибір того, що вивести. Сортувати буде сортувати весь файл незалежно від ваших потреб.
— Рубенс

18

Ну Відповідно до коментаря до відповіді shuf, він перемістив 78 000 000 000 рядків за хвилину.

Виклик прийнятий...

EDIT: Я побив власний рекорд

powerhuf зробив це за 0,047 секунди

$ time ./powershuf.py -n 10 --file lines_78000000000.txt > /dev/null 
./powershuf.py -n 10 --file lines_78000000000.txt > /dev/null  0.02s user 0.01s system 80% cpu 0.047 total

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

Gitlab Repo

Стара спроба

Спочатку мені знадобився файл з 78.000.000.000 рядків:

seq 1 78 | xargs -n 1 -P 16 -I% seq 1 1000 | xargs -n 1 -P 16 -I% echo "" > lines_78000.txt
seq 1 1000 | xargs -n 1 -P 16 -I% cat lines_78000.txt > lines_78000000.txt
seq 1 1000 | xargs -n 1 -P 16 -I% cat lines_78000000.txt > lines_78000000000.txt

Це дає мені файл із 78 мільярдами нових рядків ;-)

Тепер про частину шуфу:

$ time shuf -n 10 lines_78000000000.txt










shuf -n 10 lines_78000000000.txt  2171.20s user 22.17s system 99% cpu 36:35.80 total

Вузьке місце було процесором і не використовувало декілька потоків, воно закріпило 1 ядро ​​на 100%, інші 15 не використовувались.

Python - це те, що я регулярно використовую, ось що я використаю, щоб зробити це швидше:

#!/bin/python3
import random
f = open("lines_78000000000.txt", "rt")
count = 0
while 1:
  buffer = f.read(65536)
  if not buffer: break
  count += buffer.count('\n')

for i in range(10):
  f.readline(random.randint(1, count))

Це дістало мені трохи менше хвилини:

$ time ./shuf.py         










./shuf.py  42.57s user 16.19s system 98% cpu 59.752 total

Я зробив це на другому поколенні Lenovo X1 з i9 та Samsung NVMe, що дає мені велику швидкість читання та запису.

Я знаю, що це може пройти швидше, але я залишу трохи кімнати, щоб спробувати інших.

Джерело лічильника ліній : Лютер Бліссет


Що ж, згідно з вашим описом внутрішнього функціонування влади, виглядає, що це просто випадково. Використовуючи файл із лише двома рядками, один - 1 символом, а другий - 20 символів, я очікую, що обидва рядки будуть обрані з рівними шансами. Схоже, це не так у вашій програмі.
— xhienne
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.