You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从标准输入读取一行后将剩余内容传递给子进程?

解决Python读取stdin首行后子进程无法获取剩余输入的问题

问题现象

当Python通过sys.stdin.buffer.readline()读取标准输入首行后,启动的子进程无法读取剩余的标准输入内容。示例代码及运行结果如下:

import subprocess
import sys

header = sys.stdin.buffer.readline()
print(header)
subprocess.run(['nl'], check=True)

运行后子进程无输出:

bash$ printf '%s\n' foo bar baz | python demo1.py
b'foo\n'

但移除readline()相关代码后,子进程能正常读取所有输入:

bash$ printf '%s\n' foo bar baz | python -c 'import subprocess; subprocess.run(["nl"], check=True)'
     1  foo
     2  bar
     3  baz

问题原因

Python的标准输入默认使用块缓冲机制,当调用readline()时,操作系统会一次性读取一块数据(通常为4096字节)到Python的内部缓冲区中。剩余的输入内容会留在Python的缓冲区里,而子进程直接从操作系统的标准输入文件描述符读取数据,自然无法获取已经被Python缓冲的内容。这也解释了传入大量数据时,子进程能获取部分内容(未被Python缓冲的部分)的现象。

解决方案

方案1:手动读取剩余内容并传递给子进程

先将Python缓冲区中剩余的所有输入内容读取出来,再通过subprocess.run()的input参数传递给子进程:

import subprocess
import sys

header = sys.stdin.buffer.readline()
print(header)

# 读取剩余所有输入内容
remaining_input = sys.stdin.buffer.read()
# 将剩余内容作为子进程的输入
subprocess.run(['nl'], input=remaining_input, check=True)

运行验证:

bash$ printf '%s\n' foo bar baz | python demo1.py
b'foo\n'
     1  bar
     2  baz

方案2:禁用Python的stdin缓冲

通过调整文件描述符的属性,禁用Python对标准输入的缓冲,让readline()仅读取实际的一行数据,不预读更多内容(适用于Unix-like系统):

import subprocess
import sys
import os
import fcntl

# 获取当前stdin的文件状态标志
flags = fcntl.fcntl(sys.stdin.fileno(), fcntl.F_GETFL)
# 设置为无缓冲模式
fcntl.fcntl(sys.stdin.fileno(), fcntl.F_SETFL, flags | os.O_DIRECT)

header = sys.stdin.buffer.readline()
print(header)

subprocess.run(['nl'], check=True)

这种方法下,子进程可以直接从操作系统读取剩余的标准输入内容,无需手动传递。

方案3:使用原始文件描述符操作

直接操作stdin的原始文件描述符,绕开Python的缓冲层:

import subprocess
import sys

# 直接使用raw IO,绕过Python缓冲
raw_stdin = sys.stdin.buffer.raw
header = raw_stdin.readline()
print(header)

subprocess.run(['nl'], check=True)

sys.stdin.buffer.raw是未经Python缓冲的原始IO对象,调用其readline()不会预读数据,剩余内容会留在操作系统的stdin中,供子进程读取。


内容的提问来源于stack exchange,提问作者tripleee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 09:07:42