【问题标题】:Escaping both types of quotes in subprocess.Popen call to awk在 subprocess.Popen 对 awk 的调用中转义两种类型的引号
【发布时间】:2013-12-05 23:01:19
【问题描述】:

我的子进程调用应该调用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

【问题讨论】:

  • 看起来其中一个变量不是字符串。猜测一下,infile 可能是一个文件对象。
  • 如果我理解您的命令行正确,单引号仅用于外壳转义目的。但是由于您使用的是 Popen,它应该有 shell=False,所以您根本不需要它们,因为您没有使用 shell 来确定输入的哪些位以何种顺序进入您的外部程序。
  • @MaxNoel:由于管道(|),它在没有外壳的情况下将无法工作。你需要reproduce its functionality somehow

标签: python subprocess


【解决方案1】:

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

【讨论】:

  • 你是对的,谢谢。我很困惑,因为当我使用 ' '.join() 测试列表时,我在使用 r'' 时添加了反斜杠,我想这似乎并不重要。
  • won't help中的所有变量转换为字符串
【解决方案2】:

有几个问题。您正在尝试执行一个 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() 的参数)来提高时间性能。

【讨论】:

    猜你喜欢
    • 2011-11-13
    • 1970-01-01
    • 1970-01-01
    • 2016-05-07
    • 2012-04-11
    • 2015-07-31
    • 1970-01-01
    • 2020-12-27
    • 2012-04-09
    相关资源
    最近更新 更多