grep -n | sort | sed | cut
( export LC_ALL=C
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
) <./F
Это должно работать довольно быстро (некоторые временные тесты включены ниже) с вводом любого размера. Некоторые заметки о том, как:
export LC_ALL=C
- Поскольку целью следующей операции является получение
./Fвстроенного ./Lфайла, встроенного вместе с файлом белья, единственными символами, которые нам действительно нужно беспокоиться, являются [0-9]цифры ASCII и :двоеточие.
- По этой причине гораздо проще беспокоиться о том, чтобы найти эти 11 символов в наборе из 128 возможных, чем при использовании UTF-8.
grep -n ''
- Это вставляет строку
LINENO:в заголовок каждой строки в stdin - или <./F.
sort -t: -nmk1,1 ./L -
sortпренебрегаешь сортировать свои входные файлы на всех, и вместо этого (правильно) предполагает , что они отсортированы и -merges их в -numericallyотсортированном порядке, игнорируя в принципе ничего , кроме любого возможного -k1,1го происходящего -t:двоеточия в любом случае.
- Хотя для этого может потребоваться некоторое временное пространство (в зависимости от того, насколько далеко друг от друга могут возникать некоторые последовательности) , это не потребует большого количества по сравнению с надлежащей сортировкой, и будет очень быстрым, поскольку требует нулевого обратного отслеживания.
sortбудет выводить один поток, где любое бельё ./Lбудет сразу же предшествовать соответствующим строкам ./F. ./LЛинии всегда на первом месте, потому что они короче.
sed /:/d\;n
- Если текущая строка соответствует
/:/двоеточию, dисключите ее из выходных данных. Иначе, автоматически печатать текущую и nвнешнюю строку.
- И так
sedчернослив sortвыход «ы к только последовательные пары строк , которые не соответствуют двоеточие и следующую строку - или, только линии , ./Lа затем следующий.
cut -sd: -f2-
cut -sподавляет из вывода те его входные строки, которые не содержат по крайней мере одну из его -d:строк-элимитеров - и поэтому ./Lстроки полностью удаляются .
- Для тех строк, которые делают, их первый
:разделенный двоеточиями -field отсутствует cut- и то же самое относится ко всем grepвставленным бельям.
небольшой входной тест
seq 5 | sed -ne'2,3!w /tmp/L
s/.*/a-z &\& 0-9/p' >/tmp/F
... генерирует 5 строк ввода образца. Потом...
( export LC_ALL=C; </tmp/F \
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
)| head - /tmp[FL]
... печать ...
==> standard input <==
a-z 1& 0-9
a-z 4& 0-9
a-z 5& 0-9
==> /tmp/F <==
a-z 1& 0-9
a-z 2& 0-9
a-z 3& 0-9
a-z 4& 0-9
a-z 5& 0-9
==> /tmp/L <==
1
4
5
большие тесты по времени
Я создал пару довольно больших файлов:
seq 5000000 | tee /tmp/F |
sort -R | head -n1500000 |
sort -n >/tmp/L
... которые помещают 5 миллионов строк /tmp/Fи 1,5 миллиона случайно выбранных строк в /tmp/L. Я тогда сделал:
time \
( export LC_ALL=C
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
) <./F |wc - l
Это напечатано:
1500000
grep -n '' \
0.82s user 0.05s system 73% cpu 1.185 total
sort -t: -nmk1,1 /tmp/L - \
0.92s user 0.11s system 86% cpu 1.185 total
sed /:/d\;n \
1.02s user 0.14s system 98% cpu 1.185 total
cut -sd: -f2- \
0.79s user 0.17s system 80% cpu 1.184 total
wc -l \
0.05s user 0.07s system 10% cpu 1.183 total
(Я добавил туда обратную косую черту)
Среди решений, предлагаемых в настоящее время, это самое быстрое из всех, но одно, если оно сопоставлено с набором данных, сгенерированным выше на моей машине. Из остальных только один был близок к тому, чтобы бороться за второе место, и это мое дело perl здесь .
Это ни в коем случае не оригинальное предлагаемое решение - оно сократило треть своего времени выполнения благодаря советам / вдохновению, предлагаемым другими. Смотрите историю сообщений для более медленных решений (но почему?) .
Кроме того, стоит отметить, что некоторые другие ответы вполне могли бы бороться лучше, если бы не архитектура с несколькими процессорами моей системы и одновременное выполнение каждого из процессов в этом конвейере. Все они работают одновременно - каждое на собственном процессорном ядре - обмениваясь данными и выполняя свою небольшую часть целого. Это довольно круто.
но самое быстрое решение ...
Но это не самое быстрое решение. Самое быстрое решение, предлагаемое здесь, это программа на Си . Я назвал это cselect. После копирования его в буфер обмена X я скомпилировал его так:
xsel -bo | cc -xc - -o cselect
Я тогда сделал:
time \
./cselect /tmp/L /tmp/F |
wc -l
... и результаты были ...
1500000
./cselect /tmp/L /tmp/F \
0.50s user 0.05s system 99% cpu 0.551 total
wc -l \
0.05s user 0.05s system 19% cpu 0.551 total