【问题标题】:Find out if there is input from a pipe or not in Python?找出在 Python 中是否有来自管道的输入?
【发布时间】:2015-11-23 13:05:07
【问题描述】:

(我想)我知道如何从管道中读取数据。我的意思是像这样调用 bash

echo Bähm | ./script.py

这个 Python3 脚本可以使用它。

#!/usr/bin/env python3
import sys

x = sys.stdin.read()

if x:
    print(x)
else:
    print('no pipe')

sys.exit()

但是当我只是在 bash 上这样做时

./script.py

没有任何反应,因为它等待输入。

所以我想检查(在启动脚本时)是否有来自管道的输入。但我不知道为什么sizelensys.stdinsys.stdin.buffer 不起作用。

也许 Python 版本 2 和 3 在处理上也存在差异?

【问题讨论】:

  • 这是 Python-3.x 特有的吗?我将在标签编辑中放​​入批准或不批准。
  • 我对 Python2 一无所知。我的例子是 Python3。它们之间通常存在相关差异。这就是为什么我试图让我的问题尽可能具体。还有很多关于 SO 的 Python 问题将 2 和 3 混为一谈,让读者感到困惑。

标签: python python-3.x pipe


【解决方案1】:

@Cyrbil's answer 的替代方案如果您确实需要知道输入是否通过管道输入,您可以使用isatty

from sys import stdin
from os import isatty

is_pipe = not isatty(stdin.fileno())

【讨论】:

  • 我没有带来这个解决方案,因为我在使用 stdin.isatty() 时出现了一些意外行为,但使用 os.isatty() 这似乎工作正常。
  • @Cyrbil,我不知道你可以直接“询问”标准输入是否是 TTY。谢谢(你的)信息!我不能说有什么不同。也许 PTY 有一些奇怪的地方?
  • 好像stdin.isatty() 总是返回True。我不能产生它返回 False 的情况......所以os.isatty() 是最好的方法。
  • @Cyrbil $ echo 'No' | python -c 'from sys import stdin; print(stdin.isatty())' 为我打印 False。没有echoTrue
【解决方案2】:

没有任何反应,因为它等待输入

这完全很好。您想要修复一些不需要任何修复的东西,而作为副产品,您实际上是在制造问题。

想象一个管道过程会进行一些繁重的计算,因此需要一些时间来产生输出。您无法在 python 脚本中检查数据可用性。您不知道数据何时可用。你必须要有耐心。

所以我想检查(在启动脚本时)是否有来自 管与否。

不要。如果由于某种原因,您的应用程序不打算使用 tty(等待用户输入)运行,请检查。

sys.stdin.isatty()

仅在存在一些硬时间限制时检查数据可用性:例如:用户必须在 2 秒内做出响应。

【讨论】:

  • 这适用于我的案例。但我不确定我是否理解它背后的概念是否正确。也许在某些情况下它不能按我的预期工作?
  • 我不知道...即使检查 tty 似乎也有点过头了,尝试任何优秀的 unix 工具,catsed,...他们都会耐心等待用于用户输入。检查输入可用性 OTOH,破坏 unix 管道黑盒抽象,因为期望立即输入是不现实的。
  • less 是怎么回事?你可以说less file.txtcat file.txt | less。这不就是我想要的想法吗?
  • 在分页输出时在终端上输入确实没有意义。如果有充分的理由阻止在 tty 上运行,请继续检查。
【解决方案3】:

您可以将输入入口文件设置为非阻塞,并在没有任何管道传输时捕获IOError: [Errno 11] Resource temporarily unavailable

import fcntl
import os
import sys

# make stdin a non-blocking file
fd = sys.stdin.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

try:
    print(sys.stdin.read())
except:
    print('No input')

【讨论】:

  • 减号1。对我来说听起来真是个坏主意。如果管道过程只需要一些时间就可以产生一些输出怎么办?
  • @KarolyHorvath:这不是布赫兹要求的。他想知道是否有任何输入。 Cyrbil 的代码可能是最跨平台的方式。如果您想等待,请将他的代码放入带有计时器的循环中,直到时间到期或 read() 返回。
  • 我不会讨论 OP 说了什么。我认为我根据所提供的信息量正确回答了。你带来了一个没有引起的问题,然后在后面加上 -1。这是一种奇怪的讨论方式。
  • 你基本上只是创建一个不能解决问题的答案。然后编辑以包含 Kay 的解决方案,这将是我唯一要支持的解决方案。
  • @Cyrbil:当有人要求用枪射击另一个人时,你不会毫无疑问地把枪递给他。对我来说,这似乎是一种非常自然的讨论方式。
【解决方案4】:

您可以使用 select,但它不适用于 Windows:

import sys
import select

# Input: zero or more file-like objects
# Returns: list of objects that can be read 
def can_read_files(*args):
    return select.select(args, [], [], 0.0)[0]

if can_read_files(sys.stdin):
    print(sys.stdin.read())
else:
    print('No input')

对我们来说内联:

if select.select([sys.stdin], [], [], 0.0)[0]:
    ...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-01
    • 2011-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-12
    相关资源
    最近更新 更多