Запустите Sed для ряда строк быстрее - PullRequest
0 голосов
/ 28 октября 2019

У меня есть файл с миллионами строк. И в скрипте я хочу использовать следующую строку (которая удаляет непечатаемые символы) в цикле для заданного диапазона строк

sed -i $'s/[^[:print:]\t]//g' ~/test.txt

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

Я пробовал

sed -i $"{${line1},${line2}}{s/[^[:print:]\t]//g}" ~/test.txt

, что очень медленно для диапазона 1000 строк в конце файла

1 Ответ

1 голос
/ 28 октября 2019

Я не уверен в составе вашего тестового файла (сколько нужно замен?), Поэтому я не могу точно воспроизвести ваш тест, но я использую мой / bin / bash (1168776 байт в 5714 "строк ", с 372073 (31,8%) печатными символами / символами табуляции).

sed

(базовый уровень для целей синхронизации)

$ cp /bin/bash sh; time sed -i $'s/[^[:print:]\t]//g' sh
sed -i $'s/[^[:print:]\t]//g' sh  1.66s user 0.01s system 98% cpu 1.687 total
$ cp /bin/bash sh; time sed -i $'s/[^[:print:]\t]//g' sh
sed -i $'s/[^[:print:]\t]//g' sh  1.74s user 0.01s system 89% cpu 1.945 total
$ cp /bin/bash sh; time sed -i $'s/[^[:print:]\t]//g' sh
sed -i $'s/[^[:print:]\t]//g' sh  1.67s user 0.01s system 97% cpu 1.718 total

Среднее среднее общее время = 1,778s ? (важно запустить несколько раз для контроля за кэшированием. Я запустил четыре раза и бросил первый для учета кэширования, а затем усреднил, чтобы контролировать внешние эффекты, такие как мой веб-браузер)* Я перевел это на perl, чтобы посмотреть, будет ли это быстрее:

$ cp /bin/bash sh; time perl -i -pe $'s/[^[:print:]\t]//g' sh
perl -i -pe $'s/[^[:print:]\t]//g' sh  0.18s user 0.01s system 92% cpu 0.208 total
$ cp /bin/bash sh; time perl -i -pe $'s/[^[:print:]\t]//g' sh
perl -i -pe $'s/[^[:print:]\t]//g' sh  0.18s user 0.01s system 68% cpu 0.271 total
$ cp /bin/bash sh; time perl -i -pe $'s/[^[:print:]\t]//g' sh
perl -i -pe $'s/[^[:print:]\t]//g' sh  0.21s user 0.00s system 81% cpu 0.258 total

Среднее среднее общее время = 0,246 с ?‍

Однако я заметил некоторые различия. GNU sed испытывает трудности, возможно, из-за другого определения класса [:print:] или (более вероятно) различной обработки управляющих символов:

$ sed $'s/[^[:print:]\t]//g' /bin/bash |head -c64 |hd
00000000  45 4c 46 3e 30 f6 40 48  ce 40 38 40 40 40 40 68  |ELF>0.@H.@8@@@@h|
00000010  68 a8 a8 a8 98 cd 98 cd  d0 d0 d0 8d d7 0a 8d d7  |h...............|
00000020  0a b0 b0 b0 30 57 30 57  f0 f0 23 f0 23 b9 a8 55  |....0W0W..#.#..U|
00000030  f0 3c f0 4c f0 4c c4 c4  c4 44 44 50 e5 74 64 30  |.<.L.L...DDP.td0|
00000040
$ perl -pe $'s/[^[:print:]\t]//g' /bin/bash |head -c64 |hd
00000000  45 4c 46 3e 30 40 48 40  38 40 40 40 40 68 68 30  |ELF>0@H@8@@@@hh0|
00000010  57 30 57 23 23 55 3c 4c  4c 44 44 50 74 64 30 49  |W0W##U<LLDDPtd0I|
00000020  30 49 30 49 44 44 51 74  64 52 74 64 23 23 2c 2c  |0I0IDDQtdRtd##,,|
00000030  2f 6c 69 62 36 34 2f 6c  64 2d 6c 69 6e 75 78 2d  |/lib64/ld-linux-|
00000040

См. Все эти точки в GNU sedвыход? Это неудачи для замены контента. Я также наблюдаю это в Busybox sed. BSD sed (который используется в Mac OS X), по-видимому, не имеет этого ограничения, но учтите это для целей мобильности по мере необходимости.

tr

$ cp /bin/bash sh; time tr -cd $'[ -~\t\n]' < sh > sh-tr && mv sh-tr sh
tr -cd $'[[:print:]\t]' < sh > sh-tr  0.00s user 0.01s system 62% cpu 0.012 total
$ cp /bin/bash sh; time tr -cd $'[ -~\t\n]' < sh > sh-tr && mv sh-tr sh
tr -cd $'[[:print:]\t]' < sh > sh-tr  0.00s user 0.01s system 81% cpu 0.009 total
$ cp /bin/bash sh; time tr -cd $'[ -~\t\n]' < sh > sh-tr && mv sh-tr sh
tr -cd $'[[:print:]\t]' < sh > sh-tr  0.00s user 0.01s system 82% cpu 0.012 total

Среднее среднее значение общеговремена = 0,011 с ⚡️

Я тестировал это с GNU tr и Busybox tr (они имеют одинаковую производительность). Мы используем tr для удаления (-d) вместо tr anslate, и мы действуем на основе дополнения (-c) данного класса (tr делает )не используйте регулярное выражение, поэтому мы не можем инвертировать класс символов с помощью каретки, как мы можем в sed).

Busybox tr не поддерживает $'[[:print:]\t]', поэтому я преобразовал егов диапазоне от пробела до тильды (все печатаемые нижний ASCII, кроме табуляции и новой строки), и я добавил не только табуляцию, но и новую строку, поскольку tr необходимо явно сохранить этот символ (sed не сделал). Если строки не совпадают должным образом, рассмотрите возможность добавления \r в набор для замены.

strings здесь также хорошо, но не сохраняет строки (он заменяет каждую смежную строку непечатаемых символовс новой строкой)

...