简体   繁体   English

为什么在写入python子进程stdin管道时丢失数据?

[英]Why is data missing when I write to a python subprocess stdin pipe?

My python code looks like this: 我的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()

It calls the following simple bash shell script which simply writes stdin to a file (script is called test.sh) 它调用以下简单的bash shell脚本,该脚本仅将stdin写入文件(脚本称为test.sh)。

#!/bin/bash
VALUE=$(cat)

echo "$VALUE" >> /tmp/test.txt

When I run the python code I expect test.txt to contain the values 0x01..0x10 two times, and after that the string "endoffile" 当我运行python代码时,我希望test.txt包含两次0x01..0x10值,然后字符串“ endoffile”

However here's a hexdump of the file: 但是,这是文件的十六进制转储:

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.

It appears that a byte is missing (0x10). 似乎缺少一个字节(0x10)。

What am I missing here? 我在这里想念什么?

--- Update -更新

Changing the test() function to: 将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")

Seems to solve that. 似乎解决了。 It seems to be related to having chr(0) sent to pipe. 似乎与将chr(0)发送到管道有关。

range() is right side exclusive. range()在右侧排他。

range(0, 33) is [0, ..., 32] , probably because this way you can range(0, len(sequence)) without off-by-one errors. range(0, 33)[0, ..., 32] ,可能是因为这样您就可以range(0, len(sequence))不会出现一对一的错误。

Since 32 % 17 == 15 == 0x0f , the byte '\\x10' you are expecting was never part of the list in the first place. 由于32 % 17 == 15 == 0x0f ,因此您期望的字节'\\x10'从来没有成为列表的一部分。

Edit 1: Also missing from the output are the zero characters '\\x00' . 编辑1:输出中还缺少零字符'\\x00' If you use VALUE=$(cat) the output of cat is subject to processing by the shell. 如果您使用VALUE=$(cat)的输出cat是由外壳受到处理。

SingleUnix/POSIX seems to be silent on the matter. SingleUnix / POSIX似乎对此事保持沉默。 It is however clear, that you cannot have '\\0' as part of a shell variable's value (or name for that matter) since the Unix environment requires both to be C-style zero terminated strings . 但是很明显,您不能在shell变量的值(或名称)中包含'\\0' ,因为Unix环境要求两者都必须是C样式的零终止字符串 I actually would have expected the value of VALUE to be an empty string. 我实际上希望VALUE的值是一个空字符串。

Edit 2 After some digging, I can say that at least the ash implementation ignores '\\0' processing backtick-supplied input. 编辑2经过一番挖掘,我可以说至少ash实施忽略了'\\0'处理反引号提供的输入。 Input is read until EOF and null characters are explicitly skipped. 读取输入,直到EOF和空字符被显式跳过。

bash does the same and even has an explicit (even if commented out) warning associated with the event. bash会执行相同的操作,甚至具有与该事件关联的显式(即使已注释掉) 警告

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM