Как ускорить сценарий на основе поиска с помощью grep?

Когда вы пытались обновить, двоичные файлы armel еще не были готовы: см. содержимое пула (метки времени — это UTC AFAIK), они были загружены в 11:13 UTC. Если вы попробуете обновить обновление еще раз сейчас, оно должно работать.

Ваш sources.list несколько неполный; рекомендуемые настройки для Wheezy LTS

deb http://httpredir.debian.org/debian/ wheezy main contrib non-free
deb-src http://httpredir.debian.org/debian/ wheezy main contrib non-free

deb http://security.debian.org/ wheezy/updates main contrib non-free
deb-src http://security.debian.org/ wheezy/updates main contrib non-free

deb http://httpredir.debian.org/debian/ wheezy-updates main contrib non-free
deb-src http://httpredir.debian.org/debian/ wheezy-updates main contrib non-free

(при добавлении квалификаторов arch вы можете пропустить обновления, независимые от архитектуры).

5
04.07.2016, 23:35
5 ответов

Как уже указывалось, основная проблема здесь - это цикл оболочки. Я бы использовал awk для обработки файла журнала сначала, объединив значения id и version и сохранив результат в массиве, а затем прочитав recon. txt и в каждой строке проверьте, находится ли он в массиве, если нет - сохраните содержимое строки в переменной t и немедленно выйдите (выполнение END блокировать). В блоке END , если есть строка, сохраненная в t , тогда выйдите из 2 с сообщением, иначе просто распечатайте сообщение OK с номером. строк recon.txt :

awk 'NR==FNR{j=$9","$10;gsub(/[^0-9,]/, "", j);a[j]++;next}
!($0 in a){t=$0;{exit}}
END{if (t){print t, "FAIL"; exit 2}
else{print "All OK,", FNR, "checked"}}' logfile recon.txt

Это предполагает числовые значения для id и версии и что они всегда находятся в 9-м и 10-м поле соответственно. Если это не так, вы можете использовать регулярное выражение, такое как Sato , то есть, если ваш вариант awk поддерживает обратные ссылки, в противном случае что-то вроде этого будет:

NR==FNR{sub(/.* id=/, "");sub(/\| version=/, ",");sub(/\|.*/, ""));a[$0]++;next}
1
27.01.2020, 20:39

Я бы поместил эти файлы в БД (любого типа). Возможно, даже не импортируйте большой файл, а поместите построчно из вашего приложения, которое генерирует этот вывод.

Тогда движок БД не будет тратить ресурсы на вызов grep каждый раз, а будет использовать внутреннюю функцию, скомпилированную из C.

Не забудьте создать индексы после импорта (если вы импортируете весь файл) или после создания таблицы (если вы вставляете записи построчно).

0
27.01.2020, 20:39

Вы выполняете запрос "все из множества A, которых нет в множестве B", в дополнение к преобразованию одного множества в тот же формат, что и другое. Большинство подходов к этому требуют, на каком-то уровне, вложенных циклов.

В вашей версии вы используете grep для внутреннего цикла (проверка каждой строки в журналах), и bash для внешнего (каждая строка в recon.txt). Цикл bash каждый раз порождает несколько подоболочек и процессов, что медленно. Каждый grep обрабатывает внутренний цикл внутренне, но все равно каждый раз требует нового процесса.

Следующая строка порождает три новых процесса (две под-оболочки и col) при каждом обходе внешнего цикла:

VERSION=`echo $VERSION |col -bx`

И непонятно, какой цели это служит. Если это необходимо, то попробуйте поместить col за пределы цикла, чтобы он фильтровал весь recon.txt в одном процессе. См. также Почему использование цикла оболочки для обработки текста считается плохой практикой?. Ответ

Sato Katsura позволяет избежать вложенного цикла, сортируя оба набора входных данных, сохраняя их во временных файлах, а затем используя comm. С ограничением, что входные данные отсортированы, comm не нужно использовать вложенные циклы.

Однако для больших входных файлов временные файлы также будут большими (recon.txt переупорядочивается, т.е. выходной файл имеет тот же размер, что и входной; лог-файлы сокращаются до того же формата и переупорядочиваются). И есть время сортировки - sort использует mergesort, что в худшем случае O(n log n).

Если вы хотите избежать временных файлов и сортировки, вы можете позволить grep обрабатывать оба цикла:

cat worker-6715.log.2016-$1.log.* |
 sed 's/.*| id=\([0-9]*\)| version=\([0-9]*\)|.*/\1,\2/' |
 grep -F -x -v -f - recon.txt || ( echo -n "Lines OK: " ; wc -l < recon.txt)

Как и раньше, однократное обращение к sed (скопировано из этого ответа) преобразует формат журнала в формат recon.txt. Затем grep -v сообщает только о тех строках recon.txt, которые не были найдены в журналах. -f - берет переформатированные логи со стандартного ввода (избегая временных файлов, но означая, что grep должен держать их все в памяти). -F для поиска фиксированных строк, а не шаблонов, -x для поиска только целых строк.

Поскольку grep был инвертирован для сообщения о несовпадении, он вернет "success", если не было найдено ни одной строки. Поэтому || выведет сообщение и общее количество, только если все строки были найдены.

0
27.01.2020, 20:39

Сначала преобразуйте файл recon.txt в формат, который можно быстро использовать для grep -F:

perl -pe 's/,/| version=/' recon.txt > recon.grep-F

Тогда ваша ситуация будет описана на https://www.gnu.org/software/parallel/man. html # ПРИМЕР: -Grepping-n-lines-for-m-regular-expressions

Здесь текст адаптирован для вашей задачи:

Простейшее решение grep большого файла для большого количества регулярных выражений:

grep -f regexps.txt bigfile

Или, если регулярные выражения представляют собой фиксированные строки:

grep -F -f recon.grep-F worker.log

Есть 2 ограничивающих фактора: ЦП и дисковый ввод-вывод. ЦП легко измерить: если grep занимает> 90% ЦП (например, при работе на вершине), то ЦП является ограничивающим фактором, и распараллеливание ускорит это. Если нет, то дисковый ввод-вывод является ограничивающим фактором, и в зависимости от дисковой системы распараллеливание может быть быстрее или медленнее. Единственный способ узнать наверняка - это измерить.

Если центральный процессор является ограничивающим фактором, необходимо выполнить распараллеливание регулярных выражений:

cat recon.grep-F | parallel --pipe -L1000 --round-robin grep -F -f - worker.log

Если строка соответствует нескольким регулярным выражениям, строка может быть продублирована. Команда запускает один grep для каждого ЦП и читает большой файл один раз для ЦП, но поскольку это выполняется параллельно, все чтения, кроме первого, будут кэшироваться в ОЗУ. В зависимости от размера regexp.txt может быть быстрее использовать --block 10m вместо -L1000. Если regexp.txt слишком велик для размещения в ОЗУ, удалите --round-robin и настройте -L1000. Это приведет к тому, что bigfile будет прочитан больше раз.

Некоторые системы хранения работают лучше при параллельном чтении нескольких фрагментов. Это верно для некоторых систем RAID и некоторых сетевых файловых систем. Чтобы распараллелить чтение большого файла:

parallel --pipepart --block 100M -a worker.log -k grep -F -f recon.grep-F

Это разделит большой файл на блоки по 100 МБ и запустит команду grep для каждого из этих блоков. Чтобы распараллелить чтение bigfile и regexp.txt объединить их с помощью --fifo:

parallel --pipepart --block 100M -a worker.log --fifo cat recon.grep-F \
\| parallel --pipe -L1000 --round-robin grep -f - {}

Если строка соответствует нескольким регулярным выражениям, строка может быть продублирована.

0
27.01.2020, 20:39

Ваше узкое место - чтение файла recon.txt построчно в оболочке. Чтобы получить неудачные строки, вы можете предварительно обработать строки в логах, чтобы они выглядели как строки в recon.txt, затем использовать comm(1) для нахождения разности множеств, возможно, следующим образом:

comm -23 \
    <(sort -u recon.txt) \
    <(sed 's/.*| id=\([0-9]*\)| version=\([0-9]*\)|.*/\1,\2/' worker-6715.log.2016-$1.log.* | \
        sort -u)

Это предполагает наличие оболочки, которая может обрабатывать конструкции <(...). Также обратите внимание, что строки в результате не сохраняют порядок строк в recon.txt. Сохранить этот порядок было бы намного сложнее (и медленнее).

Если вам также нужны подсчеты успехов, вы можете сделать это наоборот, предварительно обработать recon.txt так, чтобы он был похож на то, что можно найти в журналах, а затем использовать fgrep(1) или grep -F для поиска. Установка локалей на C также может значительно ускорить работу на некоторых системах. Таким образом:

COUNT=$( \
    sed 's/\([0-9]*\),\([0-9]*\)/| id=\1| version=\2|/' recon.txt | \
    LC_ALL=C fgrep -f - worker-6715.log.2016-$1.log.* | \
    wc -l )

Это предполагает, что recon.txt не содержит дубликатов, и что каждая строка в recon.txt совпадает не более одного раза во всех журналах. Снять первое ограничение будет сложно. Второе можно снять с помощью тщательно подобранного comm(1).

4
27.01.2020, 20:39

Теги

Похожие вопросы