Bash:慢速重定向和过滤

时间:2012-04-13 18:04:42

标签: bash logging filtering redirect pipe

我有一个bash脚本调用一个生成大量输出的程序。很多这样的数据来自我没有创建的Python包,其输出我无法控制,也不感兴趣。

我尝试过滤该外部Python包生成的输出,并将“已清理”的输出重定向到日志文件。如果我使用常规管道和grep表达式,我丢失了许多信息块。我读到这是重定向(12)实际可能发生的事情。

为了解决这个问题,我做了这样的重定向:

#!/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事情)变得无法忍受。有没有办法达到同样的效果,但有更好的表现?

提前谢谢!

更新@ 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的更多不同消息,但我无法抓住任何消息。

2 个答案:

答案 0 :(得分:3)

首先,每次要添加一行时,都会重新打开日志文件。那太傻了。

而不是:

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

执行此操作(在新的非stdout文件句柄上打开输出文件,以便在您希望写入时仍然有明确的标准行:)

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

也可以为整个循环重定向stdout:

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

...值得注意的是,这不仅仅会影响“echo”行,因此与原作的语义略有不同。


或者,更好的是 - 配置the Python logging module以仅将输出过滤到您关心的内容,并且根本不需要使用shell脚本后处理。

如果你使用的Paste版本与现代Pyramid非常相似,你可以把它放在你的ini文件中(目前是parts/etc/debug.ini):

[logger_paste.httpserver.ThreadPool]
level = INFO

[logger_txn]
level = INFO

...以及INFO级以下的任何内容(包括DEBUG消息)都将被排除。

答案 1 :(得分: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之间存在很大的性能差异,但是如果有的话我就不会感到惊讶。


延迟修改

有一种更简单的方法可以解决因每行打开/关闭一次输出而导致的性能问题。为什么以前没有发生这种情况,我不知道。只需将>>移到您的循环之外

即可
#!/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解决方案更快或更慢,但它更接近原始代码并且不那么神秘。