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
пренебрегаешь сортировать свои входные файлы на всех, и вместо этого (правильно) предполагает , что они отсортированы и -m
erges их в -numerically
отсортированном порядке, игнорируя в принципе ничего , кроме любого возможного -k1,1
го происходящего -t:
двоеточия в любом случае.
- Хотя для этого может потребоваться некоторое временное пространство (в зависимости от того, насколько далеко друг от друга могут возникать некоторые последовательности) , это не потребует большого количества по сравнению с надлежащей сортировкой, и будет очень быстрым, поскольку требует нулевого обратного отслеживания.
sort
будет выводить один поток, где любое бельё ./L
будет сразу же предшествовать соответствующим строкам ./F
. ./L
Линии всегда на первом месте, потому что они короче.
sed /:/d\;n
- Если текущая строка соответствует
/:/
двоеточию, d
исключите ее из выходных данных. Иначе, автоматически печатать текущую и n
внешнюю строку.
- И так
sed
чернослив sort
выход «ы к только последовательные пары строк , которые не соответствуют двоеточие и следующую строку - или, только линии , ./L
а затем следующий.
cut -sd: -f2-
cut
-s
подавляет из вывода те его входные строки, которые не содержат по крайней мере одну из его -d:
строк-элимитеров - и поэтому ./L
строки полностью удаляются .
- Для тех строк, которые делают, их первый
:
разделенный двоеточиями -f
ield отсутствует 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