python - 独立地执行 stdout 和 stderr,不增加抖动

标签 python bash posix file-descriptor output-buffering

我想创建一个命令包装器,分别记录 stderr 和 stdout 的日志,而不更改命令的输出。不更改输出的一方面是确保 stderr 与 stdout 上的输出顺序不更改。

我创建了一个合成的最坏情况:(python -u 将解释器置于完全无缓冲模式)

$ cat outputter.py
from sys import stdout, stderr

for line in range(10):
    from itertools import izip, cycle
    for column, char, file in izip(
            range(79),
            cycle(('_', '|')),
            cycle((stdout, stderr)),
    ):
        file.write(char)
    stdout.write('\n')

$ python -u outputter.py
_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_
_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_
_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_
_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_
_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_
_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_
_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_
_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_
_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_
_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_

我可以保留两个流的记录,并通过一点 bash 相当轻松地将它们重定向回原来的目的地,但交错会被破坏:

$ python -u outputter.py > >(tee stdout.txt) 2> >(tee stderr.txt >&2)
|||_____________||||||||||_||___||_|__|||___||_|_||__||___||_||___||_|_|__||__|
__||__||_|__||_||___||_|_|_|__||__||__||_|__||_||___||__||_|_|__||_||__|__||_|_
__||__||_|__||_||___||__||_|_|_|__||_||__||___||_|__||__||__||__||_|_|___|||_|_
__|_||__||_||___||__||__||_|__||_|__||__||_||___||_|_||___||_|__||_|__||_|__||_
__|__|||_||___||_|__||_|_|__||__||_|__||_|_|___||||___||_|__||__||_||___|||___|
_|___||||___|||___||_|__|||__|_||___|||__|_||___|||___||_|__|||__||__|__||__||_
_|_||__|__|||__|_||___|||___|||___|||__|_|||____|||___||||___|_|||____|||___||_
_|__|||__|__|||__|__|||__|__|||___|||___||_|__|||__|__||_|__||_|_||___||_|__||_
_||___|||___||||___|_||___||_|__|||__||__||__|_||__||__|_|||___||___||_||__||__
_|__||_||___|||___|||__|_||__|||___||___|||___|||___||_|__||__|||___|||__|_||__

结果实际上变化很大:

$ python -u outputter.py > >(tee stdout.txt) 2> >(tee stderr.txt >&2)
_______________|||||||||||||||||||||||||||||||||_______________________||||||__
__||||____|||____|||||_____||||____|||||____|||||______||||____||||_____|||||__
_||||||||__________|||||_____||||____|||||____|||___||||_____|||||_____|||||___
_|||_____||||____||||||______|||||_____||||||_____||||_____|||||_____|||||____
|_______|||||||||____||||_____||||____|||||______|||||____|||||_____|||||____||_
||_____||||____|||||_____|||||_____||||____||||____||||___||||____||||____|||__
___|||||____|||||_____||||____|||____|||||_____|||||_____|||||_____||||____|||_
__||||_____||||____|||||_____|||||____||||_____|||||_____||||____||||____||||__
__|||____||||____||||____|||||____|||||_____||||_____||||||_____||||_____||||__
_||____|||||_____||||____|||||____||||____||||_____|||||_____||||____|||||____
|

$ python -u outputter.py > >(tee stdout.txt) 2> >(tee stderr.txt >&2)
_|||||||_______|_|||____|||__|_|__|||__|_||___|||___||_|___||||___|||__||___||_
________________________________________
________________________________________
________________________________________
________________________________________
________________________________________
________________________________________
________________________________________
________________________________________
________________________________________
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

我的问题是:是否有任何可行的方法可以做到这一点并保留原始流的交错?

另外,为什么终端没有出现同样的问题?我能想象的任何实现都会有同样的问题。

最佳答案

不,你不能那样做。这不是因为缓冲,这会产生相同的随机结果:

python -u outputter.py > >(cat -u >&2) 2> >(cat -u >&2)

问题是您的 shell 需要写入两个管道,并且它使用 select(2) 来选择要写入的管道。由于不存在填充任何管道缓冲区的危险,因此两个管道“同样可”写入,这会在两个 cat 之间创建竞争条件:第一个完成写入字符的管道获胜。比赛的结果取决于调度程序以及系统中此时发生的情况。因此具有随机性。

附带说明:如果问题与缓冲有关,那么每次都会以相同的方式得到结果乱码。

关于python - 独立地执行 stdout 和 stderr,不增加抖动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30796006/

相关文章:

python - 通过装饰器指定模型元数据(django)

python - IO错误 : No space left on device - which device?

linux - 如果输出重定向到记录器,Shell 脚本不会退出

c - errno 11 [EAGAIN] 来自 read(2)

c - 关于 vfork() 系统调用?

c - 使用 posix 函数显示所有进程

python - 向 Django 模型添加动态字段

python - 如何生成随机值的N维数组?

bash - bash 中的局部变量 : local vs subshell

linux - 使用 awk 命令用逗号替换双引号 csv 文件中的管道