Python child 脚本消耗所有标准输入
Python child script consumes all of stdin
当 运行 python 脚本在 bash 脚本中时,我发现 raw_input/readline 有一些奇怪的行为。
简而言之,当一次将所有标准输入(每个条目用新行分隔)传递给 parent 脚本时,bash child 脚本将 only 获取他们需要的标准输入,而 python child 脚本将消耗 all 标准输入,下一个 child仁。我想出了一个简单的例子来证明我的意思:
Parent 脚本 (parent.sh)
#!/bin/bash
./child.sh
./child.sh
./child.py
./child.py
Bash child 脚本 (child.sh)
#!/bin/bash
read -a INPUT
echo "sh: got input: ${INPUT}"
Python child 脚本 (child.py)
#!/usr/bin/python -B
import sys
INPUT = raw_input()
print "py: got input: {}".format(INPUT)
预期结果
./parent.sh <<< $'aa\nbb\ncc\ndd'
>> sh: got input: aa
>> sh: got input: bb
>> py: got input: cc
>> py: got input: dd
实际结果
./parent.sh <<< $'aa\nbb\ncc\ndd\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
raw_input 似乎清除了标准输入中的所有剩余行。使用 sys.stdin.readline 而不是 raw_input 不会引发 EOFError,但是收到的输入是一个空字符串,而不是预期的 'dd'.
这里发生了什么?我怎样才能避免这种行为,以便最后一个 child 脚本接收到预期的输入?
编辑:为了保险起见,我在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
}
从各方面来看,这看起来应该打印两行,但是 bar
神秘地不见了。
发生这种情况是因为阅读台词是谎言。 UNIX 编程模型不支持它。
相反,基本上所有工具所做的都是消耗整个缓冲区,分割出第一行,并将缓冲区的其余部分留给下一次调用。对于 head
、Python raw_input()
、C fgets()
、Java BufferedReader.readLine()
以及其他几乎所有内容都是如此。
由于 UNIX 将整个缓冲区计为已消耗,无论程序实际最终使用了多少,程序退出时都会丢弃缓冲区的剩余部分。
然而,bash
解决了这个问题:它逐字节读取,直到到达换行符。这是非常低效的,但它允许 read
仅使用流中的一行,将其余部分留给下一个过程。
您可以在 Python 中做同样的事情,方法是打开一个原始的、无缓冲的 reader:
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
/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
当 运行 python 脚本在 bash 脚本中时,我发现 raw_input/readline 有一些奇怪的行为。
简而言之,当一次将所有标准输入(每个条目用新行分隔)传递给 parent 脚本时,bash child 脚本将 only 获取他们需要的标准输入,而 python child 脚本将消耗 all 标准输入,下一个 child仁。我想出了一个简单的例子来证明我的意思:
Parent 脚本 (parent.sh)
#!/bin/bash
./child.sh
./child.sh
./child.py
./child.py
Bash child 脚本 (child.sh)
#!/bin/bash
read -a INPUT
echo "sh: got input: ${INPUT}"
Python child 脚本 (child.py)
#!/usr/bin/python -B
import sys
INPUT = raw_input()
print "py: got input: {}".format(INPUT)
预期结果
./parent.sh <<< $'aa\nbb\ncc\ndd'
>> sh: got input: aa
>> sh: got input: bb
>> py: got input: cc
>> py: got input: dd
实际结果
./parent.sh <<< $'aa\nbb\ncc\ndd\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
raw_input 似乎清除了标准输入中的所有剩余行。使用 sys.stdin.readline 而不是 raw_input 不会引发 EOFError,但是收到的输入是一个空字符串,而不是预期的 'dd'.
这里发生了什么?我怎样才能避免这种行为,以便最后一个 child 脚本接收到预期的输入?
编辑:为了保险起见,我在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
}
从各方面来看,这看起来应该打印两行,但是 bar
神秘地不见了。
发生这种情况是因为阅读台词是谎言。 UNIX 编程模型不支持它。
相反,基本上所有工具所做的都是消耗整个缓冲区,分割出第一行,并将缓冲区的其余部分留给下一次调用。对于 head
、Python raw_input()
、C fgets()
、Java BufferedReader.readLine()
以及其他几乎所有内容都是如此。
由于 UNIX 将整个缓冲区计为已消耗,无论程序实际最终使用了多少,程序退出时都会丢弃缓冲区的剩余部分。
然而,bash
解决了这个问题:它逐字节读取,直到到达换行符。这是非常低效的,但它允许 read
仅使用流中的一行,将其余部分留给下一个过程。
您可以在 Python 中做同样的事情,方法是打开一个原始的、无缓冲的 reader:
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
/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