Выберите случайные строки из файла


240

В скрипте Bash я хочу выделить N случайных строк из входного файла и вывести в другой файл.

Как это может быть сделано?


Сортируйте файл случайным образом и выберите N первых строк.
Петр Прасмо


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 очень неэффективен (для большого файла): лучше сделать выборку из резервуара, как в этом ответе .
буревестник

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

так что это, по сути, более случайный, чем sort -R?
Мона Джалал

1
@MonaJalal Нет, просто быстрее, так как не нужно сравнивать строки вообще.
rogerdpack

Дает ли он в итоге одну и ту же строку более одного раза?
Фредерик Норд

161

Отсортируйте файл случайным образом и выберите первые 100строки:

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

43
sortфактически сортирует одинаковые строки вместе, поэтому, если у вас могут быть повторяющиеся строки и у вас установлен shuf(инструмент gnu), лучше использовать его для этого.
Кевин

22
AndAlso, это, безусловно , будет сделать вас ждать много , если у вас есть значительно огромный файл - 80kk линии -, в то время как, shuf -nдействует совершенно мгновенно.
Рубенс

28
сортировка -R недоступна в Mac OS X (10.9)
Мирко Эберт,

3
@ tfb785: sort -Rвероятно, вариант GNU, установите GNU coreutils. Кстати, shufтакже является частью coreutils.
JFS

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

18

Ну, согласно комментарию к ответу shuf, он переставил 78 000 000 000 строк менее чем за минуту.

Вызов принят...

РЕДАКТИРОВАТЬ: я побил свой собственный рекорд

powershuf сделал это за 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 раз и печатаю строку после указателя.

Гитлаб Репо

Старая попытка

Сначала мне понадобился файл из 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 миллиардов новых строк ;-)

Теперь для части shuf:

$ 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 extreme 2-го поколения с i9 и Samsung NVMe, что дает мне много скорости чтения и записи.

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

Линия счетчик источника: Лютер Блиссетт


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