将 header 添加到 python 中子进程的标准输出

add header to stdout of a subprocess in python

我正在将几个数据帧合并为一个并使用 unix sort 对它们进行排序。在我编写最终排序数据之前,我想向该输出添加一个 prefix/header。

所以,我的代码是这样的:

my_cols =  '\t'.join(['CHROM', 'POS', "REF" ....])

my_cmd = ["sort", "-k1,2", "-V", "final_merged.txt"]

with open(output + 'mergedAndSorted.txt', 'w') as sort_data:
    sort_data.write(my_cols + '\n')  
    subprocess.run(my_cmd, stdout=sort_data)

但是,上面的 doe 将 my_cols 放在最终输出文件的末尾(即 mergedAndSorted.txt

我也试过替换:

sort_data=io.StringIO(my_cols)  

但这给了我预期的错误。


如何将 header 添加到子进程输出的开头。我相信这可以通过简单的代码更改来实现。

您的代码存在缓冲问题; tldr 是您可以这样修复它:

sort_data.write(my_cols + '\n')
sort_data.flush()
subprocess.run(my_cmd, stdout=sort_data)

如果您想了解它发生的原因,以及修复程序如何解决它:

当您以文本模式打开文件时,您打开的是一个缓冲文件。写入进入缓冲区,文件对象不一定立即将它们刷新到磁盘。 (还有从 Unicode 到字节的流编码,但这并没有真正增加新问题,它只是增加了两个可能发生同样事情的层,所以让我们忽略它。)

只要您的所有写入都写入缓冲文件对象,就可以了——它们在缓冲区中得到正确排序,因此它们在磁盘上得到正确排序。

但是,如果您写入基础 sort_data.buffer.raw 磁盘文件,或写入 sort_data.fileno() OS 文件描述符,这些写入可能会先于 [=13] =].

这正是您在 subprocess 中将文件用作管道时发生的情况。这个好像不能直接解释,但是可以从Frequently Used Arguments:

推断

stdin, stdout and stderr specify the executed program’s standard input, standard output and standard error file handles, respectively. Valid values are PIPE, DEVNULL, an existing file descriptor (a positive integer), an existing file object, and None.

这非常强烈地暗示——如果你足够了解管道在 *nix 和 Windows 上的工作方式——它将实际文件 descriptor/handle 传递给底层的 OS 功能。但它实际上并没有这么说。为了真正确定,您必须检查 the Unix source and Windows source,在那里您可以看到它正在对文件对象调用 filenomsvcrt.get_osfhandle