2014-01-23 41 views
1

我正在将this bash script转换为Python。我现在有一个可用的Python版本。然而,为了让它起作用,我必须通过将它传递给一个长字符串来破解我传递给subprocess.Popen()的命令。 我不希望使用一个长命令字符串。我想打破这个适当的个人参数。我怎样才能在的具体例子中做到这一点?将参数传递给Python子进程.Popen

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

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.") 

回答

0

这里是一个为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.") 

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

2

如果我理解你的问题corr因此,您希望将任意行从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

+0

谢谢,但我不想将任意命令行转换为Popen格式。这不是我的问题。我试图让上面的脚本以正确的方式工作。这是一个具体的问题,不是一般的问题。你能说明如何写上面的脚本吗?谢谢 – MountainX

+0

我更新了我的问题,使其更清楚。谢谢 – MountainX

4

如果您最初的例子中,你是传递“shell = True”,那么这个注释在the docs是相关的:

shell参数(默认为False)指定是否使用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 
+0

我试过“shell = False”,该命令不起作用,我也没有看到任何错误消息。使用“shell = True”,我至少能够看到错误消息... – MountainX

+1

subprocess.Popen(['ls -l'],shell = False)将不起作用,因为这将查找名为“ls -l”的可执行文件,该可执行文件不存在。当使用“shell = False”时,应该传递不同字符串中的每个arg,一个la:subprocess.Popen(['ls','-l'],shell = False) – Potrebic

+0

谢谢,但我仍然无法弄清楚如何将此信息应用于上面的脚本。 – MountainX