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

240

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

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

user121196
источник
Сортируйте файл случайным образом и выберите N первых строк.
Петр Прасмо
Также см. Stackoverflow.com/questions/12354659/… .
Acumenus
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
user881480
источник
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