【问题标题】:Print python stdout to stdout将 python 标准输出打印到标准输出
【发布时间】:2013-05-01 14:11:20
【问题描述】:

这有点难以解释,所以我提前道歉。

我有一个用 Python 编写的命令行应用程序。它记录到标准错误和标准输出;日志过滤器配置如下:

class StdErrFilter(logging.Filter):
    def filter(self,record):
        return 1 if record.levelno >= 30 else 0

class StdOutFilter(logging.Filter):
    def filter(self,record):
        return 1 if record.levelno <= 20 and record.levelno > 10 else 0 

设置日志的函数如下所示:

def setup_logging(logger_name):
    logger = logging.getLogger(logger_name)
    logger.setLevel(logging.DEBUG)

    formatter = logging.Formatter(fmt=LOG_FMT)

    err_handler = logging.StreamHandler(sys.__stderr__)
    err_handler.addFilter(StdErrFilter())
    err_handler.setFormatter(formatter)
    logger.addHandler(err_handler)

    out_handler = logging.StreamHandler(sys.__stdout__)
    out_handler.addFilter(StdOutFilter())
    out_handler.setFormatter(formatter)
    logger.addHandler(out_handler)

    return logger

当应用程序被直接调用时,它会按我的预期工作,即info() 及以下打印到标准输出,warn() 及以上打印到标准错误。但是,当在 bash 脚本中进行完全相同的调用时,info 及以下内容不会打印到终端,但 stderr 仍然按预期工作。我可以将脚本管道标准输出到文件,但不能到终端。有什么想法吗?

EDIT 我也应该显示 bash 脚本。还有一些其他逻辑与在那里为 Python 应用程序构建 args 相关,但实际调用在 for 循环的底部附近。请注意,Python 应用程序是一个可执行模块。

#!/bin/bash

# provide one argument, the directory to search for ".xml" files.
dir_to_index=$1

FIND=/usr/bin/find
PYTHON=/usr/bin/python

SOLR="http://localhost:8983/solr/pul-development" 

BIN="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

marc_to_solr=$BIN/../marc_to_solr
PYTHONPATH=$marc_to_solr:$PYTHONPATH

db_config=$BIN/../etc/database.ini
config=db_config=$BIN/../etc/config.ini

for f in `$FIND $dir_to_index -name "*.xml"`; do
    echo "File: $f"
    cmd="$PYTHON -m marc_to_solr -d $db_config -s $SOLR -c etc/config.ini -i $f"
    `$cmd`
done

【问题讨论】:

  • 你是如何从你的 bash 脚本中调用它的?
  • Duh...我应该在我的问题中证明这一点。以上编辑。

标签: python bash logging stdout


【解决方案1】:

问题出在一行

`$cmd`

bash 中的反引号表示将标准输出重定向到内部 bash 缓冲区,您可以将其包含在另一个命令中或分配给 bash 变量。 只需省略反引号,它就会达到您的预期。

【讨论】:

  • 显然 /me 使用 Python 要好得多。谢谢!
【解决方案2】:

我相信问题在于您的 python 脚本的调用。通过将$cmd 放在刻度中,您是在告诉 bash 将程序的stdout 输出作为 bash 命令运行。这是我能想到的最简单的情况

echo 'import sys
sys.stdout.write(str(1))
sys.stderr.write(str(2))' > test.py

cmd='python test.py'

现在我们可以尝试几种不同的方式调用它

# If you invoke it like this, it works fine
$cmd
# And this will work, too
bash -c "$cmd"
# If you invoke it like this, you'll get some complaints
`$cmd`

【讨论】: