如果从sys.stdin开始为readline(),则将其其余部分传递给子进程似乎不起作用.

import subprocess
import sys

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

(我使用sys.stdin.buffer来避免任何编码问题;该句柄返回原始字节.)

这会运行,但我没有从子进程中获得任何输出;

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

如果我go 掉readline个ETC,子流程将读取标准输入并生成我预期的输出.

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

当我开始阅读标准输入的其余部分时,是不是Python在缓冲它,或者这里发生了什么?用python -u运行并不能解决这个问题(实际上,它的文档只提到它改变了stdoutstderr的行为).但如果我传递更多的数据,我确实会得到一些数据:

bash$ wc -l /etc/services
   13921 /etc/services

bash$ python demo1.py </etc/services  | head -n 3
     1     27/tcp     # NSW User System FE
     2  #                          Robert Thomas <BThomas@F.BBN.COM>
     3  #                28/tcp    Unassigned
 (... traceback from broken pipe elided ...)

bash$  fgrep -n 'NSW User System FE' /etc/services 
91:nsw-fe           27/udp     # NSW User System FE
92:nsw-fe           27/tcp     # NSW User System FE

bash$ sed -n '1,/NSW User System FE/p' /etc/services | wc
      91     449    4082

(因此,看起来它从开始就占用了4096个字节.)

不过,我有没有办法避免这种行为呢?我只想从头开始读一行,然后将其余内容传递给子过程.

在循环中重复拨打sys.stdin.buffer.readline(-1)不会有任何帮助.

这实际上是Read line from shell pipe, pass to exec, and keep to variable的后续问题,但我想把重点放在这个问题中令我惊讶的方面.

推荐答案

这是因为在默认缓冲模式下使用内置open函数时,sys.stdincreated,该模式使用大小为io.DEFAULT_BUFFER_SIZE的缓冲区,在大多数系统上,缓冲区大小为40968192字节.

因此,要使父进程恰好使用标准输入中的一行文本,您可以通过将0作为buffering参数传递给openos.fdopen函数来禁用缓冲区来打开它:

# subp1.py
import os
import sys
import subprocess

# or with the platform-dependent device file:
# unbuffered_stdin = open('/dev/stdin', 'rb', buffering=0)
unbuffered_stdin = os.fdopen(sys.stdin.fileno(), 'rb', buffering=0)

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

因此:

printf "foo\nbar\n" | python subp1.py

然后输出:

b'foo\n'
     1  bar

Python相关问答推荐

ambda将时间戳与组内另一列的所有时间戳进行比较

Pythind 11无法弄清楚如何访问tuple元素

Polars比较了两个预设-有没有方法在第一次不匹配时立即失败

Django管理面板显示字段最大长度而不是字段名称

Python daskValue错误:无法识别的区块管理器dask -必须是以下之一:[]

根据另一列中的nan重置值后重新加权Pandas列

如何列举Pandigital Prime Set

如何使用表达式将字符串解压缩到Polars DataFrame中的多个列中?

计算分布的标准差

如何在turtle中不使用write()来绘制填充字母(例如OEG)

判断solve_ivp中的事件

如何在PySide/Qt QColumbnView中删除列

提高算法效率的策略?

Discord.py -

如何使用正则表达式修改toml文件中指定字段中的参数值

如何在Python Pandas中填充外部连接后的列中填充DDL值

使用嵌套对象字段的Qdrant过滤

在我融化极点数据帧之后,我如何在不添加索引的情况下将其旋转回其原始形式?

我怎么才能用拉夫分拣呢?

有了Gekko,可以创建子模型或将模型合并在一起吗?