使用sys.stdin.readline()

时间:2017-04-08 09:27:42

标签: python linux bash shell

我正在做一些需要使用curl xxx | bash运行的东西。 我用sys.stdin.readline()创建了一个python脚本来测试这样:

[python3] test.py


import sys
def read_input():
    input = sys.stdin.readline().rstrip()
    print(input)
read_input()

它直接由python3 test.py

运行
test
test

但如果我使用echo 'python3 test.py' | bash,我就不会停止让我输入内容。

任何提示?

1 个答案:

答案 0 :(得分:2)

使用|进行管道传输时,您将第一个命令的输出重定向到第二个命令的输入。这意味着第二个命令的标准输入不连接到终端,因此无法读取键盘输入。因此,curl xxx | bash形式仅适用于非交互式脚本。这绝不是Python特有的。

原则上你可以通过将输入描述符保存在另一个数字下来解决这个问题,但它确实变得非常复杂:

$ ( echo 'exec <&3 3<&- ; echo script starts ; read hello ; echo you entered $hello ; exit' | bash ) 3<&0
script starts
something
you entered something

在这里,我使用()创建了一个子shell,其中stdin在文件描述符3上使用3<&0复制,并且管道中生成的脚本都将其重命名为stdin {{1} }和exec <&3 3<&-以防止从恢复的标准输入读取更多命令。这有副作用,例如为exit命令打开描述符3。

由于首先使用echo的主要原因是保持命令简单,这不是你所追求的。此外,如果下载过程中出现任何问题,管道会阻止您处理;你的脚本可以在任何地方中断。传统的下载运行并没有那么糟糕:

curl address | bash

相比之下,这会将curl -O http://somewhere/somefile.py && python somefile.py 保存到您的文件系统中。这有一些缺点,比如需要一个可写的文件系统并替换那个特定的文件名。从好的方面来说,如果出现任何问题,由于somefile.py,它会停在那里并且不会运行损坏的脚本。

如果你正在下载的脚本符合命令行,那么最后一种可能是将它放在那里而不是放在管道中:

&&

这与中断的下载具有相同的弱点,并且另外将脚本内容放在命令行中,该命令行通常是公共信息(考虑python -c "$(curl $url)" 输出)。但是,如果您只是使用curl下载脚本,那么有关如何获取该脚本的信息也是如此。由于这并没有重定向stdin,因此它可能是您当前问题的答案。

一般情况下,我建议直接在互联网上运行任何脚本而不进行验证,因为此ps ax命令行会执行此操作。它太容易受到劫持,因为任何步骤都不涉及验证。使用检查签名的包存储库(例如apt)会更好。

在Linux上访问终端的另一种方法是通过设备/dev/tty。此方法用于实例when ssh asks for a password。也可以重新打开stdout或stderr进行输入,如curl something | bash中所示。