【问题标题】:python subprocess.call() modifies arguments before passing it to shell-script?python subprocess.call() 在将参数传递给shell脚本之前修改参数?
【发布时间】:2017-06-07 09:24:10
【问题描述】:

我正在编写一个 python 包装器,用于调用 AMOS 包的程序(特别是用于使用来自 AMOS 的良好 ol' minimus2 合并来自不同来源的基因组程序集)。

直接使用shell时脚本应该这样调用:

toAmos -s myinput.fasta -o testoutput.afg
minimus2 testoutput -D REFCOUNT=400 -D OVERLAP=500

[只是为了澄清:

-toAmos:将我的 input.fasta 文件转换为 .afg 格式并需要一个输入序列参数(“-s”)和一个输出参数(“-o”)

-minimus2:将序列数据集与参考重叠群合并,需要一个参数“-D REFCOUNT=x”来说明输入中的参考序列的数量,以及一个参数“-D OVERLAP=Y”来说明序列之间的最小重叠]

所以在我的脚本中,我使用 subprocess.call() 来调用必要的 AMOS 工具。

基本上我是这样做的:

from subprocess import call:
output_basename = "testoutput"
inputfile = "myinput.fasta"

call(["toAmos", "-s " + inputfile, "-o " + output_basename + ".afg"])
call(["minimus2", output_basename, "-D REFCOUNT=400", "-D OVERLAP=500"])

但在这种情况下,AMOS 工具无法再解释参数。参数似乎被 subprocess.call() 修改并错误传递。我得到的错误信息是:

Unknown option: s myinput.fasta
Unknown option: o testoutput.afg
You must specify an output AMOS AFG file with option -o
/home/jov14/tools/miniconda2/bin/runAmos: unrecognized option '-D REFCOUNT=400'
Command line parsing failed, use -h option for usage info

似乎参数在没有前导“-”的情况下通过了?所以我然后尝试将命令作为单个字符串(包括参数)传递,如下所示:

call(["toAmos -s " + inputfile +" -o " + output_basename + ".afg"])

然后我得到这个错误......

OSError: [Errno 2] No such file or directory

...大概是因为 subprocess.call 将整个字符串解释为单个脚本的名称。 我想我可以尝试shell=True 作为一种解决方法,但互联网上充满了明确建议不要这样做的说明。

这里似乎有什么问题? 我能做什么?

【问题讨论】:

    标签: python bash shell subprocess amos


    【解决方案1】:

    回答

    要么做:

    call("toAmos -s " + inputfile +" -o " + output_basename + ".afg") # single string
    

    或者做:

    call(["toAmos", "-s", inputfile, "-o", output_basename + ".afg"]) # list of arguments
    

    讨论

    如果是您的:

    call(["toAmos", "-s " + inputfile, "-o " + output_basename + ".afg"])
    

    你应该提供:

    • "-s" + inputfile-s 后面没有空格)、"-o" + output_basename + ".afg"
    • "-s", inputfile(单独的参数),"-o", output_basename + ".afg"

    如果是您的:

    call(["minimus2", output_basename, "-D REFCOUNT=400", "-D OVERLAP=500"])
    

    "-D REFCOUNT=400""-D OVERLAP=500" 应分别作为两个项目提供 ('-D', 'REFCOUNT=400', '-D', 'OVERLAP=500'),或删除空格 ('-DREFCOUNT=400', '-DOVERLAP=500')。

    附加信息

    您似乎缺乏关于 shell 如何拆分命令行的知识;我建议您始终使用单字符串方法,除非文件名中有空格或者您必须使用shell=False 选项;在这种情况下,我建议您始终提供参数列表。

    【讨论】:

    • 第一个选项对我不起作用(请参阅上面帖子末尾的“没有这样的文件”错误)。但第二个选项是一个很大的帮助。我没有意识到您必须分别传递参数标志和相应的参数。谢谢
    • 啊,好的。抱歉,刚刚意识到您将字符串不是作为列表传递的。不知何故,我从示例中收集到 subprocess.call() 只接受列表,并且一个没有参数的简单命令必须作为只有一个项目的列表调用。感谢您的澄清。
    【解决方案2】:

    -s 和以下输入文件名应该是 call 的单独参数,因为它们在命令行中:

    call(["toAmos", "-s", inputfile, "-o", output_basename + ".afg"])
    

    【讨论】:

    • 啊,好的。我必须分别传递所有标志和相应的参数字符串!我以为我必须将每个标志及其各自的论点一起传递。傻我。谢谢!
    • 你通常可以传递每个标志及其各自的参数,如果你这样做在选项字母后添加一个空格。选项解析库通常需要一个命令行参数"-oOPTION_ARGUMENT" 或两个命令行参数"-o", "OPTION_ARGUMENT"。这是 shell 在命令调用时提供的内容,您也应该提供。在选项字母和选项参数之间添加一个空格就像在 shell 中输入'grep' '-F' '-e your_pattern';这不是预期的,也不会起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-15
    • 2011-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多