2012-04-13 3 views
0

У меня есть сценарий bash, который вызывает программу, которая генерирует огромное количество выходных данных. Многие из этих данных поступают из пакета Python, который я еще не создал, и выход которого я не могу контролировать и не интересует.Bash: медленное перенаправление и фильтр

Я попытался отфильтровать вывод, сгенерированный этим внешним пакетом Python, и перенаправить «очищенный» вывод в файл журнала. Если бы я использовал регулярные трубы и выражения grep, я потерял много фрагментов информации. Я читал, что это может произойти с перенаправлением (1 и 2).

Для того, чтобы исправить это, я сделал переназначения так:

#!/bin/bash 
regexTxnFilterer="\[txn\.-[[:digit:]]+\]" 
regexThreadPoolFilterer="\[paste\.httpserver\.ThreadPool\]" 
bin/paster serve --reload --pid-file="/var/run/myServer//server.pid" parts/etc/debug.ini 2>&1 < "/dev/null" | while IFS='' read -r thingy ; do 
     if [[ ! "$thingy" =~ $regexTxnFilterer ]] && [[ ! "$thingy" =~ $regexThreadPoolFilterer ]]; then 
        echo "$thingy" >> "/var/log/myOutput.log" 
     fi 
done 

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

Проблема в том, что она предоставила приложение (bin/paster вещь, которую я выполняю) невыносимо медленно. Есть ли способ добиться такого же эффекта, но с лучшей производительностью?

Спасибо заранее!

Update @ 2012-04-13: Как shellter отметил в одном из комментариев на этот вопрос, может быть полезно привести примеры выходов, которые я хочу, чтобы отфильтровать. Вот связка из них:

2012-04-13 19:30:37,996 DEBUG [txn.-1220917568] new transaction 
2012-04-13 19:30:37,997 DEBUG [txn.-1220917568] commit <zope.sqlalchemy.datamanager.SessionDataManager object at 0xbf4062c> 
2012-04-13 19:30:37,997 DEBUG [txn.-1220917568] commit 
Starting server in PID 18262. 
2012-04-13 19:30:38,292 DEBUG [paste.httpserver.ThreadPool] Started new worker -1269716112: Initial worker pool 
2012-04-13 19:33:08,158 DEBUG [txn.-1244144784] new transaction 
2012-04-13 19:33:08,158 DEBUG [txn.-1244144784] commit 
2012-04-13 19:32:06,980 DEBUG [paste.httpserver.ThreadPool] Added task (0 tasks queued) 
2012-04-13 19:32:06,980 INFO [paste.httpserver.ThreadPool] kill_hung_threads status: 10 threads (0 working, 10 idle, 0 starting) ave time N/A, max time 0.00sec, killed 0 workers 

Там в нескольких более различных сообщениях, вовлекающих ThreadPool, хотя, но я не мог поймать любого.

+1

Рассмотрите возможность обновления вашего вопроса, чтобы включить некоторые значения образца для $ thingy, которые вы хотите пропустить. Я предполагаю, что есть более эффективный reg-ex, который можно применить к вашему делу. Кроме того, рассмотрите использование 'sed' в качестве вашего фильтра вместо цикла' while read thingy'. Удачи. – shellter

+0

Хм. более сложный, чем я ожидал. Можете ли вы переиздать и добавить окончательный блок, например, требуемый вывод, учитывая 10 строк, которые вы опубликовали. Является ли «запуск сервера ...» действительно ли это собственной отдельной линией? Удачи. – shellter

+1

oh, еще одна вещь, которую вы можете сделать сразу, чтобы ускорить ваше регулярное выражение, предполагает, что ваш заголовок журнала «всегда» похож на «2012-04-13 19: 30: 37,996 DEBUG» - это привязать reg ex к перед линией, и укажите любые 30 символов, т. е. '/ ^. \ {30 \} \ [txn \ .- [[: digit:]] + \]'. Возможно, вам придется экспериментировать, может быть, это действительно '/ ^. {30} /' (без экранирования '\' символов перед {}. ИЛИ наихудший случай '/^........... ................... \ [txn \ .- [[: digit:]] + \] /. 'Я все еще думаю, что' sed' - лучший инструмент для это для вашей строки INFO, напомните, что '.?' означает ноль или один из символов preceing. Удачи. – shellter

ответ

1

Это может быть быстрее использовать Grep на основе решения этой

#!/bin/bash 
regexTxnFilterer="\[txn\.-[[:digit:]]+\]" 
regexThreadPoolFilterer="\[paste\.httpserver\.ThreadPool\]" 
bin/paster serve --reload --pid-file="/var/run/myServer//server.pid" parts/etc/debug.ini 2>&1 < "/dev/null" | grep -vf <(echo "$regexTxnFilterer"; echo "$regexThreadPoolFilterer") >> "/var/log/myOutput.log" 

ваш цикл может быть медленным, потому что echo "$thingy" >> "/var/log/myOutput.log" линия открытия и закрытия лог-файл каждый раз, когда он выполняет. Я бы не ожидал большой разницы в производительности между сочетанием регулярных выражений grep и bash, но если бы это было, это меня не удивило бы.


Late Edit

Там есть гораздо более простой способ решить проблему производительности, вызванной открытием/закрытием выход один раз в каждой строке. Почему это раньше не приходило в голову, я понятия не имею. Просто переместите >> к вне вашего цикла

#!/bin/bash 
regexTxnFilterer="\[txn\.-[[:digit:]]+\]" 
regexThreadPoolFilterer="\[paste\.httpserver\.ThreadPool\]" 
bin/paster serve --reload --pid-file="/var/run/myServer//server.pid" parts/etc/debug.ini 2>&1 < "/dev/null" | while IFS='' read -r thingy ; do 
     if [[ ! "$thingy" =~ $regexTxnFilterer ]] && [[ ! "$thingy" =~ $regexThreadPoolFilterer ]]; then 
        echo "$thingy" 
     fi 
done >> "/var/log/myOutput.log" 

Я не вижу каких-либо веских причин, почему это будет быстрее или медленнее, чем grep решение, но это гораздо ближе к исходному коду и немного менее загадочны ,

+0

Кажется, это работает немного лучше ... моя единственная забота заключается в том, что когда я пробовал «регулярные» перенаправления, я потерял линии ...Вот почему вывод «завернут» в блок while/done. Я буду следить за ним, посмотрим, работает ли он нормально. – BorrajaX

+0

@BorrajaX нормально, я надеюсь, что это сработает. Я не могу понять, почему это было бы иначе, если только. Взяв второй взгляд на это, есть более простое изменение вашего кода, которое исправит проблему open/close. Я отредактирую свой ответ. – je4d

+0

@BorrajaX отредактирован. Мне было бы интересно узнать, как эти два решения выше для вас, по сравнению друг с другом – je4d

3

С одной стороны, вы повторно открываете файл журнала каждый раз, когда хотите добавить строку. Это глупо.

Вместо этого:

while ...; do 
    echo "foo" >>filename 
done 

ли это (который открывает файл вывода на дескриптор файла новый, не стандартный вывод, так что вы по-прежнему иметь четкую линию на стандартный вывод, если вы хотите написать ему):

exec 4>>filename 
while ...; do 
    echo "foo" >&4 
done 

Это также можно перенаправить стандартный вывод для всего цикла:

while ...; do 
    echo "foo" 
done >filename 

... Nota bly, это повлияет не только на линию «эхо», и, следовательно, будет иметь немного отличающуюся семантику от оригинала. еще


Или, лучше - Настройка the Python logging module фильтровать вывод только то, что вы заботитесь о, и не заморачиваться с оболочечной сценария постобработки на всех.

Если версия Paste вы используете достаточно похожа на современную пирамиде, вы можете поместить это в ини файле (в настоящее время parts/etc/debug.ini):

[logger_paste.httpserver.ThreadPool] 
level = INFO 

[logger_txn] 
level = INFO 

... и все, что ниже уровня INFO (включая сообщения DEBUG) будут исключены.

+0

Даже если я попытаюсь установить уровень для ThreadPool и logger_txn в своих частях/etc/debug.ini, файл журнала все еще показывает нежелательные сообщения. – BorrajaX

+0

@BorrajaX Мне нужно будет увидеть файл в полном объеме (или, по крайней мере, связанные с протоколированием биты), чтобы отладить это - честно говоря, это, вероятно, материал для другого вопроса (один не помеченный 'bash'). И снова, что я дал здесь, для Pyramid, не тестировалось ни в одной другой основе Paste. –

+0

Да, ты прав. Я использую grok (у которого есть Zope внизу). Спасибо за подсказки. – BorrajaX