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


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.