Вот альтернативный метод и небольшой бенчмаркинг, добавленный к этому в ответе Weijun Zhou .
join
Предполагая, что у вас есть файл data
, из которого вы хотите извлечь строки, и файл line_numbers
, в котором перечислены номера строк, которые вы хотите извлечь, если порядок сортировки вывода не важен, вы можете использовать:
join <(sort padded_line_numbers) <(nl -w 12 -n rz data) | cut -d ' ' -f 2-
Это пронумерует строки вашего файла data
, соединит его с файлом padded_line_numbers
в первом поле (по умолчанию )и распечатает общие строки (, исключая само поле соединения, что вырезано ).
join
требует, чтобы входные файлы были отсортированы по алфавиту. Вышеупомянутый файл padded_line_numbers
должен быть подготовлен путем заполнения слева -каждой строки вашего файла line_numbers
. Например.:
while read rownum; do
printf '%.12d\n' "$rownum"
done padded_line_numbers
Опции и аргументы -w 12 -n rz
предписывают nl
выводить 12-значные числа с ведущими нулями.
Если порядок сортировки вывода должен совпадать с порядком сортировки вашего файла line_numbers
,вы можете использовать:
join -1 2 -2 1 <(nl padded_line_numbers | sort -k 2,2) \
<(nl -w 12 -n rz data) |
sort -k 2,2n |
cut -d ' ' -f 3-
Где мы нумеруем файл padded_line_numbers
, сортируем результат в алфавитном порядке по его второму полю, соединяем его с пронумерованным файлом data
и численно сортируем результат по исходному порядку сортировки padded_line_numbers
.
Подстановка процессов здесь используется для удобства. Если вы не можете или не хотите полагаться на него и, скорее всего, не хотите тратить память, необходимую для создания обычных файлов для хранения промежуточных результатов, вы можете использовать именованные каналы :
.
mkfifo padded_line_numbers
mkfifo numbered_data
while read rownum; do
printf '%.12d\n' "$rownum"
done padded_line_numbers &
nl -w 12 -n rz data >numbered_data &
join -1 2 -2 1 padded_line_numbers numbered_data | sort -k 2,2n | cut -d ' ' -f 3-
Поскольку особенностью вашего вопроса является количество строк в вашем data
файле, я подумал, что было бы полезно протестировать альтернативные подходы с сопоставимым объемом данных.
Для тестов я использовал файл данных размером 3,2 миллиарда строк. Каждая строка представляет собой всего 2 байта мусора, поступающего из openssl enc
, шестнадцатеричный -, закодированный с помощью od -An -tx1 -w2
и с удаленными пробелами с помощью tr -d ' '
:
.
$ head -n 3 data
c15d
061d
5787
$ wc -l data
3221254963 data
Файл line_numbers
был создан путем случайного выбора 10 000 чисел от 1 до 3 221 254 963 без повторений с использованием shuf
из GNU Coreutils:
shuf -i 1-"$(wc -l line_numbers
Средой тестирования был ноутбук с четырехъядерным -процессором i7 -2670QM Intel, 16 ГиБ памяти, хранилищем SSD, GNU/Linux, bash
5.0 и инструментами GNU.
Единственным измерением, которое я измерил, было время выполнения с помощью встроенной оболочки time
.
Вот думаю:
sed
из ответа Weijun Zhou . awk
из ответа Миши . perl
из ответа Вюртеля . join
выше. perl
кажется, самый быстрый:
$ time perl_script line_numbers data | wc -l
10000
real 14m51.597s
user 14m41.878s
sys 0m9.299s
awk
производительность выглядит сопоставимой:
$ time awk 'FNR==NR { seen[$0]++ }; FNR!=NR && FNR in seen' line_numbers data | wc -l
10000
real 29m3.808s
user 28m52.616s
sys 0m10.709s
join
, тожекажется сопоставимым:
$ time join <(sort padded_line_numbers) <(nl -w 12 -n rz data) | wc -l
10000
real 28m24.053s
user 27m52.857s
sys 0m28.958s
Обратите внимание, что отсортированная версия, упомянутая выше, почти не имеет снижения производительности по сравнению с этой.
Наконец, sed
кажется значительно медленнее :Я убил его примерно через девять часов:
$ time sed -nf <(sed 's/$/p/' line_numbers) data | wc -l
^C
real 551m12.747s
user 550m53.390s
sys 0m15.624s
TCP реализован независимо от уровня канала передачи данных. Таким образом, пакет TCP может охватывать один или несколько кадров Ethernet.
Если вы хотите отфильтровать на уровне канала передачи данных, а также проверить более высокие уровни сетевой связи, вам потребуется собрать связь TCP вручную из составных кадров канала данных, а затем проверить информацию уровня 3.
Кадры Ethernet имеют стандартные размеры, поэтому сборка пакетов из фреймов не должна быть такой сложной, и вы можете обнаружить, что большинство шагов квитирования TCP сами по себе могут поместиться в один фрейм Ethernet, но если вы работаете с носителем 802.11 это может стать гораздо более сложной задачей, поскольку уровень 2 может быть зашифрован между клиентами Wi-Fi и точками доступа.