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

时间:2015-09-21 16:25:01

标签: 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()

它调用以下简单的bash shell脚本,它只是将stdin写入文件(脚本称为test.sh)

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

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

当我运行python代码时,我希望test.txt包含值0x01..0x10两次,之后字符串" endoffile"

然而,这里是文件的hexdump:

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)发送到管道有关。

1 个答案:

答案 0 :(得分:1)

range()是右侧专有。

range(0, 33)[0, ..., 32],可能是因为这样你可以range(0, len(sequence))没有一个错误。

32 % 17 == 15 == 0x0f开始,您期望的字节'\x10'从未成为列表中的一部分。

编辑1: 输出中也缺少零个字符'\x00'。如果您使用VALUE=$(cat)cat的输出将由shell处理。

SingleUnix / POSIX似乎对此事保持沉默。但很明显,由于Unix环境要求两者都是C-style zero terminated strings,因此不能将'\0'作为shell变量值(或该名称的名称)的一部分。实际上,我希望VALUE的值为空字符串。

编辑2 经过一番挖掘,我可以说至少ash implementation忽略'\0'处理反引号提供的输入。读取输入,直到明确跳过EOF和空字符。

bash做同样的事情,甚至有与事件相关的明确(即使已注释掉)warning