Python子脚本使用所有stdin

Python子脚本使用所有stdin,python,linux,bash,stdin,Python,Linux,Bash,Stdin,在bash脚本中运行python脚本时,我发现raw_input/readline有一些奇怪的行为 简言之,当一次将所有stdin(每个条目由新行分隔)传递给父脚本时,bash子脚本将只获取它们所需的stdin,而python子脚本将消耗所有stdin,不会为下一个子脚本留下任何内容。我举了一个简单的例子来说明我的意思: 父脚本(Parent.sh) Bash子脚本(child.sh) Python子脚本(child.py) 预期结果 /parent.sh sh:get输入:aa >>sh:获得

在bash脚本中运行python脚本时,我发现raw_input/readline有一些奇怪的行为

简言之,当一次将所有stdin(每个条目由新行分隔)传递给父脚本时,bash子脚本将只获取它们所需的stdin,而python子脚本将消耗所有stdin,不会为下一个子脚本留下任何内容。我举了一个简单的例子来说明我的意思:

父脚本(Parent.sh) Bash子脚本(child.sh) Python子脚本(child.py) 预期结果
/parent.sh sh:get输入:aa
>>sh:获得输入:bb
>>py:get输入:cc
>>py:get输入:dd
实际结果
/parent.sh sh:get输入:aa
>>sh:获得输入:bb
>>py:get输入:cc
>>回溯(最近一次呼叫最后一次):
>>文件“/child.py”,第5行,在
>>输入=原始输入()
>>EOF:读取一行时的EOF
原始输入似乎会清除stdin中的所有剩余行。使用sys.stdin.readline而不是原始输入不会引发EOFEROR,但是收到的输入是空字符串,而不是预期的“dd”

这里发生了什么?如何避免这种行为,使最后一个子脚本接收到预期的输入

编辑:为了确保这一点,我在stdin中又添加了几行,结果是一样的:

./parent.sh <<< $'aa\nbb\ncc\ndd\nff\nee\n'
>> sh: got input: aa
>> sh: got input: bb
>> py: got input: cc
>> Traceback (most recent call last):
>>   File "./child.py", line 5, in <module>
>>     INPUT = raw_input()
>> EOFError: EOF when reading a line
/parent.sh sh:get输入:aa
>>sh:获得输入:bb
>>py:get输入:cc
>>回溯(最近一次呼叫最后一次):
>>文件“/child.py”,第5行,在
>>输入=原始输入()
>>EOF:读取一行时的EOF

这里有一个更简单的方法来演示相同的问题:

printf "%s\n" foo bar | {
    head -n 1
    head -n 1
}
据所有人说,这看起来应该打印两行,但是
神秘地丢失了

这是因为读台词是谎言。UNIX编程模型不支持它

相反,基本上所有工具都会消耗整个缓冲区,划出第一行,剩下的缓冲区留给下一次调用。这适用于
head
、Python
raw_input()
、C
fgets()
、Java
BufferedReader.readLine()
以及几乎所有其他内容

由于UNIX将整个缓冲区计算为已消耗,因此无论程序实际使用了多少缓冲区,程序退出时都会丢弃剩余的缓冲区

然而,
bash
解决了这个问题:它一个字节一个字节地读取,直到到达换行符。这是非常低效的,但是它允许
read
只使用流中的一行,将其余的保留下来供下一个进程使用

在Python中,您可以通过打开一个原始的、无缓冲的读取器来执行相同的操作:

import sys
import os
f = os.fdopen(sys.stdin.fileno(), 'rb', 0)
line=f.readline()[:-1]
print "Python read: ", line
我们可以用同样的方法进行测试:

printf "%s\n" foo bar | {
    python myscript
    python myscript
}
印刷品

Python read: foo
Python read: bar

默认情况下,python解释器将缓冲标准输入。您可以使用
-u
选项禁用此行为,尽管其效率较低

parent.sh 输出
/parent.sh如果使用
dd\n
会发生什么情况?在读取输入时,您会在
中省略dd;也要执行…
循环,因为末尾没有空白新行。。。尝试按@hustmphrr建议插入一个。。。FWIW您可以通过读取-a INPUT | |[“$INPUT”]do…
来修复bash案例,我确信python也有类似的功能,但我不知道等价性,我已经调整了上面的答案以避免这种混淆。最初,我在测试时的行数超过了所需的行数,在编辑问题时删除了太多行数。请参见上面的编辑。完美。这就是我想要的方式。使用
f.readline()
,然后从字符串末尾剥离换行符,似乎可以获得相同的结果。谢谢你的解释。啊,我不懂Python,所以我不知道那会有用。更方便。我不知道-u选项。奇怪的是,-u选项的帮助字符串没有提到stdin。我选择上面的解决方案是因为它更全面(而且可能更有效),但是这个解决方案很好,因为它不需要对脚本进行任何更改。
./parent.sh <<< $'aa\nbb\ncc\ndd\nff\nee\n'
>> sh: got input: aa
>> sh: got input: bb
>> py: got input: cc
>> Traceback (most recent call last):
>>   File "./child.py", line 5, in <module>
>>     INPUT = raw_input()
>> EOFError: EOF when reading a line
printf "%s\n" foo bar | {
    head -n 1
    head -n 1
}
import sys
import os
f = os.fdopen(sys.stdin.fileno(), 'rb', 0)
line=f.readline()[:-1]
print "Python read: ", line
printf "%s\n" foo bar | {
    python myscript
    python myscript
}
Python read: foo
Python read: bar
/bin/bash

./child.sh
./child.sh
python -u child.py
python -u child.py
./parent.sh <<< $'aa\nbb\ncc\ndd'
sh: got input: aa
sh: got input: bb
py: got input: cc 
py: got input: dd