【问题标题】:Passing parameters to Python subprocess.Popen将参数传递给 Python subprocess.Popen
【发布时间】:2014-02-13 11:14:58
【问题描述】:

我正在将 this bash script 转换为 Python。我现在有一个可用的 Python 版本。然而,为了让它工作,我不得不破解我传递给 subprocess.Popen() 的命令,把它变成一个长字符串。 我不想使用一个长命令字符串。我希望将其分解为适当的单个参数。在这个 specific 示例中,我该如何做到这一点?

我的具体问题是如何更改这一行:

process = subprocess.Popen(cmd, shell=True, ...

变成这样的形式:

process = subprocess.Popen([prog, inf, arate, outf], shell=False, ...

这是我的完整代码,以便上面的片段有意义:

#!/usr/bin/env python

import sys
import subprocess
import os.path
import argparse #requires Python 2.7 or above

parser = argparse.ArgumentParser(description='Converts (.M4V) videos into (.MP3) audio files using ffmpeg.')
parser.add_argument('-d','--directory', help='Source directory name',required=True)
parser.add_argument('-o','--output',help='Output directory name', required=False)
parser.add_argument('-a','--arate',help='ffmpeg\'s arate option', default="64K", required=False)
parser.add_argument('-s','--source',help='Input type; e.g., file ext (default .m4v)', default=".m4v", required=False)
parser.add_argument('-e','--ext',help='Output type; e.g., file ext (default .mp3)', default=".mp3", required=False)
parser.add_argument('-p','--program',help='application program e.g., /usr/bin/ffmpeg', default="/usr/bin/ffmpeg", required=False)
args = parser.parse_args()

arate = args.arate
source = args.source
new_ext = args.ext                                                                                                                                             
prog = args.program
in_path = args.directory

if(not args.output):
    out_path = in_path
else:
    out_path = args.output

if(not os.path.isfile(prog)):
    print("Command {} does not exist".format(prog))

else:
    try:
        filenames = os.listdir(in_path)
        for file in filenames:
            print("name={}\nextension={}".format(name, extension))
            if(extension == source):
                inf = os.path.join(in_path, file)
                outf = os.path.join(out_path, name + new_ext)
                cmd = "{xprog} -i '{xpath}' -b:a {art} -vn '{xout}'".format(xprog=prog, xpath=inf, art=arate, xout=outf)
                process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
                stdout,stderr = process.communicate()
                return_code = process.poll()
                print("stdout='{}'\nstderr='{}'\nreturn_code='{}'".format(stdout, stderr, return_code))
    except IOError as e:
        print("Error: file not found.")

【问题讨论】:

    标签: python linux bash shell popen


    【解决方案1】:

    如果我正确理解您的问题,那么您想将 bash 脚本中的任意行转换为 Popen 接受的格式。

    Python 文档有一个很好的(并且隐藏得很好) 示例,说明如何做到这一点。 来自:http://docs.python.org/2/library/subprocess.html#popen-constructor

    >>> import shlex, subprocess
    >>> command_line = raw_input()
    /bin/vikings -input eggs.txt -output "spam spam.txt" -cmd "echo '$MONEY'"
    >>> args = shlex.split(command_line)
    >>> print args
    ['/bin/vikings', '-input', 'eggs.txt', '-output', 'spam spam.txt', '-cmd', "echo '$MONEY'"]
    

    现在我们可以在实践中应用上述信息:

    import shlex
    command = "/usr/bin/ffmpeg -i 'in_path/in_file.ext' -b:a arate -vn 'out_path/out_file.ext'"
    print command
    # /usr/bin/ffmpeg -i 'in_path/in_file.ext' -b:a arate -vn 'out_path/out_file.ext'
    popen_cmd = shlex.split(command)
    print popen_cmd
    # ['/usr/bin/ffmpeg', '-i', 'in_path/in_file.ext', '-b:a', 'arate', '-vn', 'out_path/out_file.ext']
    

    虽然使用os.system 可能更容易

    【讨论】:

    • 谢谢,但我不想将任意命令行转换为 Popen 格式。那不是我的问题。我试图让上面的脚本以正确的方式工作。这是一个具体的问题,不是笼统的。你能展示一下上面的脚本应该怎么写吗?谢谢
    【解决方案2】:

    如果在您的初始示例中您传递“shell=True”,那么the docs 中的此注释是相关的:

    shell 参数(默认为 False)指定是否使用 shell 作为 要执行的程序。如果 shell 为 True,建议将 args 作为字符串传递,而不是 作为一个序列

    在这种情况下:

    subprocess.Popen(['ls -l'], shell=True)
    

    结果:

    total 1416
    -rw-r--r--   1 me  AD\Domain Users      17 Nov  3 01:17 file1
    drwxr-xr-x   7 me  AD\Domain Users     238 Jan 22 15:34 dir
    -rw-r--r--   1 me  AD\Domain Users     368 Nov 14 22:39 file2.xml
    

    【讨论】:

    • 我尝试了“shell=False”,但该命令不起作用,我也没有看到任何错误消息。使用“shell=True”,我至少能够看到错误消息...
    • subprocess.Popen(['ls -l'], shell=False) 将不起作用,因为这将查找名为“ls -l”的可执行文件,但它不存在。使用 "shell=False" 时,应在不同的字符串中传递每个参数,例如:subprocess.Popen(['ls', '-l'], shell=False)
    • 谢谢,但我仍然无法弄清楚如何将此信息应用到我上面的脚本中。
    【解决方案3】:

    这是一个完整的工作解决方案,带有适当的 Popen() 参数。

    import subprocess
    import os.path
    import argparse #requires Python 2.7 or above
    
    parser = argparse.ArgumentParser(description='Converts (.M4V) videos into (.MP3) audio files using ffmpeg.')
    parser.add_argument('-d','--directory', help='Source directory name',required=True)
    parser.add_argument('-o','--output',help='Output directory name', required=False)
    parser.add_argument('-a','--arate',help='ffmpeg\'s arate option', default="64K", required=False)
    parser.add_argument('-s','--source',help='Input type; e.g., file ext (default .m4v)', default=".m4v", required=False)
    parser.add_argument('-e','--ext',help='Output type; e.g., file ext (default .mp3)', default=".mp3", required=False)
    parser.add_argument('-p','--program',help='application program e.g., /usr/bin/ffmpeg', default="/usr/bin/ffmpeg", required=False)
    args = parser.parse_args()
    
    arate = args.arate
    source = args.source
    new_ext = args.ext                                                                                                                                             
    prog = args.program
    in_path = args.directory
    
    if(not args.output):
        out_path = in_path
    else:
        out_path = args.output
    
    if(not os.path.isfile(prog)):
        print("Command {} does not exist".format(prog))
    
    else:
        try:
            filenames = os.listdir(in_path)
            for file in filenames:
                name, extension = os.path.splitext(file)
                if(extension == source):
                    print("Processing: {}".format(file))
                    inf = os.path.join(in_path, file)
                    outf = os.path.join(out_path, name + new_ext)
                    process = subprocess.Popen([prog, "-i", inf, "-b:a", arate, "-vn", outf], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
                    stdout,stderr = process.communicate()
                    return_code = process.poll()
                    print("stdout='{}'\nstderr='{}'\nreturn_code='{}'".format(stdout, stderr, return_code))
                else:
                    print("Skipping: {}".format(file))
    
        except IOError as e:
            print("Error: file not found.")
    

    如果有人对此有改进,请告诉我!

    【讨论】:

      猜你喜欢
      • 2017-02-18
      • 1970-01-01
      • 1970-01-01
      • 2016-09-08
      • 1970-01-01
      • 2015-07-09
      • 2013-12-07
      • 2018-01-11
      • 2010-09-14
      相关资源
      最近更新 更多