【问题标题】:Python crashing at `input(...)` after reading from STDIN从 STDIN 读取后,Python 在 `input(...)` 处崩溃
【发布时间】:2020-08-14 20:48:14
【问题描述】:

这不会崩溃:

import sys
print(len(sys.stdin.read()))

但这会崩溃:

import sys
print(len(sys.stdin.read()))
input('lol')

有输出

2300
lolTraceback (most recent call last):
  File "test018.py", line 3, in <module>
    input('lol')
EOFError: EOF when reading a line

问题:

  • 为什么?
  • 如何正确操作?我的目标是从 STDIN 读取一些数据(例如cat somefile | myscript),然后提示用户一些事情(例如hey, does this look right?)。

【问题讨论】:

  • python 2 中的输入就是这样做的。输入内容时会崩溃吗?
  • input() 也从 sys.stdin 读取。由于您使用管道,您不能再使用input() 来读取用户的输入。您可以改为直接打开/dev/tty 进行读写。
  • 如果你只是从 shell 运行myscript,它根本不会触及标准输入。在 fork 之后(在实际执行程序之前),子进程拥有父进程的所有打开文件描述符。如果没有管道,shell 只是执行 myscript 并且它仍然有那些 fds。但是由于cat somefile | myscript中有管道,所以在fork之后它会关闭stdin并替换管道的fd,然后执行程序。外壳本身不知道管道何时关闭,也没有机会替代其他任何东西。它现在只是两个连接程序的业务。
  • @caveman - 大部分是的。文件描述符是底层 c 库中表的整数索引。在手波伪代码中,shell 打开一个管道并获取文件描述符 4 和 5。它分叉并关闭 0 和 5,因为它不需要它们。然后它将 4 复制到 0,这意味着文件描述符表条目 4 被复制到 0。然后它关闭 4 以清除该表条目。然后它执行新程序。现在,当新程序使用文件描述符 0 时,它会在文件描述符表中获取已移动到 0 的管道条目。
  • 按照 alaniwi 的建议访问控制 TTY 是 unix 上的常见解决方案。在使用 PIPE 运行时禁用交互更为常见,假设它在不需要提示的脚本中运行。你也可以使用像 tkinter 这样的 gui 并尝试弹出一些东西。或者编写自己的脚本来执行命令,myscript "cat somefile"。你的建议很有趣,但我不知道如何实现它。

标签: python linux stdin prompt


【解决方案1】:

您已经从标准输入读取到文件末尾,但您可以从终端设备读取:

import sys
print(len(sys.stdin.read()))

print("lol ", end="")
sys.stdout.flush()
answer = open("/dev/tty").readline().replace("\n", "")
print("You typed:", answer)

如果您还通过管道传输标准输出,那么您可能希望类似地将提示写入终端设备(请注意,您必须打开它才能写入),尽管此示例使用普通的print 到标准输出。

【讨论】:

  • 谢谢。是的,所有提示都在 TTY 上是有道理的。但是还有更多跨平台的方式吗?或者至少没有我手动编写路径“/dev/tty”的东西,因为我猜 TTY 可能不在那个路径中?例如。 getpass() 我猜是这样。但不确定它是否有非密码对应项。
  • @caveman TBH,看来您使用的是类 Unix 系统,所以我不太担心跨平台。恐怕我不知道在 Linux 以外的系统上可能会调用什么终端设备,或者如何更便携地执行此操作,但/dev/tty 在 Linux 系统上相当可靠。
  • 我采用了这个方案:stackoverflow.com/questions/7141331/…
猜你喜欢
  • 2021-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-27
  • 1970-01-01
  • 1970-01-01
  • 2012-08-11
相关资源
最近更新 更多