如何将一个python脚本的输出传递给另一个python脚本

Dar*_*ark 5 python

我陷入了将一个脚本的输出传递到另一个脚本(两个都是python)的问题.

这个问题非常相似,但(1)它没有提供答案(2)我的情况略有不同.所以,我认为开一个新问题会更好.

这是问题所在.
两个脚本几乎完全相同:

receiver.py

import sys
import time

for line in sys.stdin:
    sys.stdout.write(line)
    sys.stdout.flush()
    time.sleep(3)
Run Code Online (Sandbox Code Playgroud)

replicator.py

import sys
import time

for line in sys.stdin:
    sys.stderr.write(line)
    sys.stderr.flush()
    time.sleep(3)
Run Code Online (Sandbox Code Playgroud)

当我一个接一个地在bashcmd中执行这些脚本时,一切都很好.以下两个示例都正常工作,我在输出中看到输入文本:

作品:(每3秒输出一行输出)

cat data.txt | python receiver.py
cat data.txt | python replicator.py
Run Code Online (Sandbox Code Playgroud)

但是一旦我从一个脚本管道到另一个脚本,它们就会停止工作:

不起作用:(在到达文件末尾之前没有任何内容出现)

cat data.txt | python receiver.py | python replicator.py
Run Code Online (Sandbox Code Playgroud)

然后,当我将第一个脚本传递给另一个工具时,它再次工作!

作品:

cat data.txt | python receiver.py | cat -n
cat data.txt | python replicator.py | cat -n
Run Code Online (Sandbox Code Playgroud)

最后,当我删除阻塞sleep()函数时,它再次开始工作:

删除计时器:

time.sleep(0)
Run Code Online (Sandbox Code Playgroud)

它现在有效:

cat data.txt | python receiver.py | python replicator.py
Run Code Online (Sandbox Code Playgroud)

有人知道我的管道有什么问题吗?我不是在寻找替代方法.我只想了解这里发生的事情.

UPDATE

根据评论,我改进了这些例子.
现在这两个脚本不仅打印出内容data.txt,还为每一行添加时间戳.

receiver.py

import sys
import time
import datetime

for line in sys.stdin:
    sys.stdout.write(str(datetime.datetime.now().strftime("%H:%M:%S"))+'\t')
    sys.stdout.write(line)
    sys.stdout.flush()
    time.sleep(1)
Run Code Online (Sandbox Code Playgroud)

data.txt中

Line-A
Line-B
Line-C
Line-D
Run Code Online (Sandbox Code Playgroud)

结果

$> cat data.txt
Line-A
Line-B
Line-C
Line-D

$> cat data.txt | python receiver.py
09:05:44        Line-A
09:05:45        Line-B
09:05:46        Line-C
09:05:47        Line-D

$> cat data.txt | python receiver.py | python receiver.py
09:05:54        09:05:50        Line-A
09:05:55        09:05:51        Line-B
09:05:56        09:05:52        Line-C
09:05:57        09:05:53        Line-D

$> cat test.log | python receiver.py | sed -e "s/^/$(date +"%H:%M:%S") /"
09:17:55        09:17:55        Line-A
09:17:55        09:17:56        Line-B
09:17:55        09:17:57        Line-C
09:17:55        09:17:58        Line-D

$> cat test.log | python receiver.py | cat | python receiver.py
09:36:21        09:36:17        Line-A
09:36:22        09:36:18        Line-B
09:36:23        09:36:19        Line-C
09:36:24        09:36:20        Line-D
Run Code Online (Sandbox Code Playgroud)

正如您所看到的那样,当我将python脚本的输出传递给它自己时,第二个脚本会一直等到第一个脚本完成.然后它开始消化数据.

但是,当我使用其他工具(sed在此示例中)时,该工具会立即接收数据.为什么会这样?

Jua*_*doy 1

这是由于文件对象( )中的内部缓冲造成的。for line in sys.stdin

因此,如果我们逐行获取

import sys
import time
import datetime

while True:
    line = sys.stdin.readline()
    if not line:
       break
    sys.stdout.write(str(datetime.datetime.now().strftime("%H:%M:%S"))+'\t')
    sys.stdout.write(line)
    sys.stdout.flush()
    time.sleep(1)
Run Code Online (Sandbox Code Playgroud)

该代码将按预期工作:

$ cat data.txt | python receiver.py |  python receiver.py
09:43:46        09:43:46        Line-A
09:43:47        09:43:47        Line-B
09:43:48        09:43:48        Line-C
09:43:49        09:43:49        Line-D
Run Code Online (Sandbox Code Playgroud)

文档

...请注意,file.readlines() 和文件对象(对于 sys.stdin 中的行)中有内部缓冲,不受此选项的影响。要解决此问题,您需要在 while 1: 循环内使用 file.readline() 。

注意:这个问题在Python 3File Object中已修复

  • @Dark - 不是的,它只是以 `readline()` 的方式工作 - 它读取流,直到遇到 `\n` ,此时返回缓冲区。另一方面,“for line in handle”期望句柄是一个可迭代的,并且 Pyhon 在开始发送单个元素之前等待很长一段时间(即等待缓冲区被填充)。此行为已得到修复,但从 STDIN 读取时仅使用 readlines() 仍然是一个更安全的选择。(顺便说一句,你根本不需要`-u`,它也不会帮助你,因为你无论如何都会立即刷新你的 STDOUT/STDERR ) (2认同)