如何直接在控制台上对文件进行子处理(使用或不使用StringIO)?

时间:2017-04-14 16:36:25

标签: python subprocess popen stringio

我正在尝试读取一个gtf文件,然后在加载到pandas之前对其进行编辑(使用subprocess,grep和awk)。

我有一个包含标题信息的文件名(由#表示),所以我需要先将其删除并先将其删除。我可以在python中完成它,但我想在我的管道中引入grep以提高处理效率。

我尝试过:

import subprocess
from io import StringIO

gtf_file = open('chr2_only.gtf', 'r').read()
gtf_update = subprocess.Popen(["grep '^#' " + StringIO(gtf_file)], shell=True)

gtf_update = subprocess.Popen(["grep '^#' " + gtf_file], shell=True)

这两个代码都会抛出错误,第一次尝试是:

Traceback (most recent call last):
  File "/home/everestial007/PycharmProjects/stitcher/pHASE-Stitcher-Markov/markov_final_test/phase_to_vcf.py", line 39, in <module> gtf_update = subprocess.Popen(["grep '^#' " + StringIO(gtf_file)], shell=True)
TypeError: Can't convert '_io.StringIO' object to str implicitly

但是,如果我直接指定文件名,它可以工作:

gtf_update = subprocess.Popen(["grep '^#' chr2_only.gtf"], shell=True)

,输出为:

<subprocess.Popen object at 0x7fc12e5ea588>
#!genome-build v.1.0
#!genome-version JGI8X
#!genome-date 2008-12
#!genome-build-accession GCA_000004255.1
#!genebuild-last-updated 2008-12

有人可以提供这样的问题的不同示例,并解释为什么我会收到错误以及为什么/如何直接在控制台/内存上加载的文件上运行子进程?

我也尝试将subprocesscall, check_call, check_output, etc.一起使用,但我收到了几条不同的错误消息,例如:

OSError: [Errno 7] Argument list too long

Subprocess in Python: File Name too long

1 个答案:

答案 0 :(得分:2)

这是一个可能的解决方案,允许您将字符串发送到grep。基本上,您在Popen构造函数中声明要通过stdin和stdout与被调用程序进行通信。然后通过通信发送输入,并从通信接收输出作为返回值。

#!/usr/bin/python

import subprocess

gtf_file = open('chr2_only.gtf', 'r').read()
gtf_update = subprocess.Popen(["grep '^#' "], shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)

# stdout, stderr (but latter is empty)
gtf_filtered, _ = gtf_update.communicate(gtf_file)

print gtf_filtered

请注意,不使用shell=True是明智的。因此,Popen行应写为

gtf_update = subprocess.Popen(["grep", '^#'], shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE)

理由是你不需要shell来解析单个可执行文件的参数。所以你避免了不必要的开销从安全的角度来看,它也更好,至少如果某些参数可能不安全,因为它来自用户(想想包含|的文件名)。 (这显然不是这种情况。)

请注意,从性能的角度来看,我希望直接使用grep读取文件比首先使用python读取文件,然后将其发送到grep。