在subprocess.Popen调用awk中转义两种类型的引号

时间:2013-12-05 23:01:20

标签: python subprocess

我的子进程调用应该调用tabix 1kg.phase1.snp.bed.gz -B test.bed | awk '{FS="\t";OFS="\t"} $4 >= 10',但由于其中包含"',因此给出了错误。我尝试使用r作为原始字符串,但我无法找出正确的组合来防止错误。我目前的电话看起来像:

snp_tabix = subprocess.Popen(["tabix", tgp_snp, "-B", infile, "|", "awk", """'{FS="\t";OFS="\t"}""", "$4", ">=", maf_cut_off, r"'"], stdout=subprocess.PIPE)

出现错误TypeError: execv() arg 2 must contain only strings

2 个答案:

答案 0 :(得分:3)

r"'"不是问题。您很可能将maf_cut_off作为整数传递,这是不正确的。您应该使用str(maf_cut_off)

答案 1 :(得分:1)

有几个问题。您正在尝试执行shell命令(命令中有一个管道|)。因此即使将所有变量转换为字符串也无法工作。

您可以使用shell执行它:

from pipes import quote
from subprocess import check_output

cmd = r"""tabix %s -B %s | awk '{FS="\t";OFS="\t"} $4 >= %d'""" % (
    quote(tgp_snp), quote(infile), maf_cut_off)
output = check_output(cmd, shell=True)

或者您可以使用pipe recipe from subprocess' docs

from subprocess import Popen, PIPE

tabix = Popen(["tabix", tgp_snp, "-B", infile], stdout=PIPE)
awk = Popen(["awk", r'{FS="\t";OFS="\t"} $4 >= %d' % maf_cut_off],
            stdin=tabix.stdout, stdout=PIPE)
tabix.stdout.close() # allow tabix to receive a SIGPIPE if awk exits
output = awk.communicate()[0]
tabix.wait()

或者您可以使用plumbum that provides some syntax sugar for shell commands

from plumbum.cmd import tabix, awk

cmd = tabix[tgp_snp, '-B', infile]
cmd |= awk[r'{FS="\t";OFS="\t"} $4 >= %d' % maf_cut_off]
output = cmd() # run it and get output

另一种选择是在纯Python中重现awk命令。要使第4个字段的所有行以数字方式大于或等于maf_cut_off(作为整数):

from subprocess import Popen, PIPE

tabix = Popen(["tabix", tgp_snp, "-B", infile], stdout=PIPE)
lines = []
for line in tabix.stdout:
    columns = line.split(b'\t', 4)
    if len(columns) > 3 and int(columns[3]) >= maf_cut_off:
       lines.append(line)
output = b''.join(lines)
tabix.communicate() # close streams, wait for the subprocess to exit

tgp_snpinfile应为字符串,maf_cut_off应为整数。

您可以使用bufsize=-1Popen()的参数)来提高时间效果。