我陷入了将一个脚本的输出传递到另一个脚本(两个都是python)的问题。
这question非常相似,但(1)它没有提供答案(2)我的情况略有不同。所以,我认为开一个新问题会更好。
这是问题所在 两个脚本几乎完全相同:
receiver.py
import sys
import time
for line in sys.stdin:
sys.stdout.write(line)
sys.stdout.flush()
time.sleep(3)
replicator.py
import sys
import time
for line in sys.stdin:
sys.stderr.write(line)
sys.stderr.flush()
time.sleep(3)
当我一个接一个地在 bash 或 cmd 中执行这些脚本时,一切都很好。以下两个示例都正常工作,我在输出中看到输入文本:
作品(每3秒钟会出现一行输出)
cat data.txt | python receiver.py
cat data.txt | python replicator.py
但是一旦我从一个脚本管道到另一个脚本,他们就会停止工作:
不能工作(在到达文件末尾之前不会显示任何内容)
cat data.txt | python receiver.py | python replicator.py
然后,当我将第一个脚本传递给另一个工具时,它再次工作!
使用:
cat data.txt | python receiver.py | cat -n
cat data.txt | python replicator.py | cat -n
最后,当我删除阻塞sleep()函数时,它再次开始工作:
删除计时器:
time.sleep(0)
现在可行:
cat data.txt | python receiver.py | python replicator.py
有人知道我的滚边有什么问题吗? 我不是在寻找替代方法。我只是想了解这里发生了什么。
根据评论,我对例子进行了改进
现在,这两个脚本不仅打印出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)
data.txt中
Line-A
Line-B
Line-C
Line-D
结果
$> 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
正如您所看到的,当我将python脚本的输出传递给它自己时,第二个脚本会一直等到第一个脚本完成。然后它开始消化数据。
但是,当我使用其他工具(在此示例中为sed
)时,该工具会立即接收数据。为什么会这样?
答案 0 :(得分: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)
代码将按预期工作:
$ 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
...请注意,file.readlines()和File中有内部缓冲 对象( for sys.stdin 中的行)不受此影响 选项。要解决此问题,您将需要使用file.readline() 在一段时间内1:循环。
注意:在Python 3
中修复了File Object
内容