为什么在写入python子进程stdin管道时会丢失数据?
我的python代码如下所示:为什么在写入python子进程stdin管道时会丢失数据?,python,bash,pipe,subprocess,Python,Bash,Pipe,Subprocess,我的python代码如下所示: def test(): pipe = sp.Popen( ["test.sh"], stdin=sp.PIPE) data = "".join([chr((s)%17) for s in range(0,33)]) os.write(pipe.stdin.fileno(), data) pipe.stdin.write("endoffile") if __name__ == "__main__": test() 它调用以
def test():
pipe = sp.Popen( ["test.sh"], stdin=sp.PIPE)
data = "".join([chr((s)%17) for s in range(0,33)])
os.write(pipe.stdin.fileno(), data)
pipe.stdin.write("endoffile")
if __name__ == "__main__":
test()
它调用以下简单的bashshell脚本,该脚本只将stdin写入一个文件(该脚本称为test.sh)
当我运行python代码时,我希望test.txt包含值0x01..0x10两次,然后是字符串“endoffile”
但是,这里有一个文件的hextump:
0000000: 0102 0304 0506 0708 090a 0b0c 0d0e 0f10 ................
0000010: 0102 0304 0506 0708 090a 0b0c 0d0e 0f65 ...............e
0000020: 6e64 6f66 6669 6c65 0a ndoffile.
似乎缺少一个字节(0x10)
我错过了什么
---更新
将test()函数更改为:
def test():
pipe = sp.Popen( ["test.sh"], stdin=sp.PIPE)
data = "".join([chr((s)%16+1) for s in range(0,32)])
os.write(pipe.stdin.fileno(), data)
pipe.stdin.write("endoffile")
似乎解决了这个问题。
这似乎与将chr(0)发送到管道有关。range()
是右侧独占的
范围(0,33)
是[0,…,32]
,可能是因为这样您可以范围(0,len(序列))
而不会出现一个关闭错误
由于32%17==15==0x0f
,因此您期望的字节'\x10'
从一开始就不在列表中
编辑1:
输出中还缺少零字符'\x00'
。如果使用VALUE=$(cat)
则cat
的输出由shell处理
SingleUnix/POSIX似乎对此保持沉默。但是,很明显,您不能将'\0'
作为shell变量值(或名称)的一部分,因为Unix环境要求两者都是。实际上,我希望value
的值是一个空字符串
编辑2
经过一些挖掘,我可以说,至少会忽略'\0'
处理backtick提供的输入。读取输入,直到显式跳过EOF和null字符
bash执行相同的操作,甚至有一个与事件关联的显式(即使已注释掉)。dhke-您是正确的,但是off by one错误在另一侧-缺少一个条目。我怀疑这是由于通过管道发送chr(0)-它被丢弃。知道为什么吗?@sferic我甚至没有意识到\0
也不见了,谢谢你提醒我。请参阅编辑。在设计的示例中,test.sh包含一行代码的解决方案是:cat>/tmp/test.txt
。问题不在于cat
的输出会发生分词(不是分词),而是空字节会过早终止字符串。Shell并不是设计用来处理任意二进制数据的。@chepner啊,没错,=
不进行分词。这实际上让我更加确信,这只是一个你不能以任何方式依赖的未记录的副作用。
def test():
pipe = sp.Popen( ["test.sh"], stdin=sp.PIPE)
data = "".join([chr((s)%16+1) for s in range(0,32)])
os.write(pipe.stdin.fileno(), data)
pipe.stdin.write("endoffile")