【发布时间】: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"。你的建议很有趣,但我不知道如何实现它。