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рядком в рядку з файлом lineno, єдині символи, про які нам дійсно потрібно буде турбуватися, - це [0-9]цифри ASCII і :двокрапка.
- З цієї причини легше турбуватися про те, щоб знайти ці 11 символів у наборі з 128 можливих, ніж це, якщо UTF-8 іншим чином залучений.
grep -n ''
- Це вставляє рядок
LINENO:у голову кожного рядка в stdin - або <./F.
sort -t: -nmk1,1 ./L -
sortнехтує взагалі сортування вхідних файлів, а натомість (правильно) припускає, що вони -mскасовуються та видаляє їх у -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«вставляють LINENO років.
невеликий вхідний тест
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
... які помістили 5mil рядків у /tmp/Fта 1,5mil випадковим чином вибраних ліній у /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
(Я додав туди косої риски)
Серед пропонованих тут рішень, це найшвидший з усіх, але один, коли він відповідає набору даних, згенерованих вище на моїй машині. З інших тільки один був близький до претендують на друге місце, і це meuh ось perl тут .
Це аж ніяк не оригінальне пропоноване рішення - воно втратило третину часу його виконання завдяки порадам / натхненню, запропонованим іншими. Дивіться історію публікацій для повільніших рішень (але чому?) .
Крім того, варто відзначити, що деякі інші відповіді можуть бути набагато кращими, якби не архітектура з декількома процесорами моєї системи та одночасне виконання кожного з процесів у цьому конвеєрі. Всі вони працюють одночасно - кожен у своєму ядрі процесора - передаючи дані та виконуючи свою невелику частину цілого. Це досить круто.
але найшвидше рішення -
Але це не найшвидше рішення. Найшвидше рішення пропонується тут, руки вниз, це програма C . Я це назвав 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