Python子进程参数带引号

1 投票
2 回答
2217 浏览
提问于 2025-04-17 22:06

我想从Python中运行一个叫做http://mediaarea.net/en/MediaInfo的命令行工具。这个工具接受一些参数,使用起来很简单。

*简单用法: *

# verbose all info
MediaInfo.exe test.mp4 

模板用法:

# verbose selected info from csv    
MediaInfo.exe --inform="file://D:\path\to\csv\template.csv" test.mp4 

我想用模板参数来运行它。我可以在命令提示符(CMD)中成功使用上面的命令。它运行得很好,我可以在DOS窗口中看到我选择的输出。

但是当我尝试从Python中运行它时,它输出了所有的信息,而忽略了我作为参数提供的CSV文件。有人能解释一下为什么吗?是因为引号的问题吗?

注意: 如果CSV的路径不正确或者CSV文件无效,MediaInfo会输出所有的信息,这正是现在发生的情况。

#App variable is full path to MediaInfo.exe
#filename variable is full path to media file

proc  =  subprocess.Popen([App ,'--inform="file://D:\path\to\csv\template.csv"',filename],shell=True,stderr=subprocess.PIPE, stdout=subprocess.PIPE) 
return_code = proc.wait()
for line in proc.stdout:
    print line

2 个回答

0

如果你用 print 打印你的参数,你可能会看到哪里出错了:

>>> print '--inform="file://D:\path\to\csv\template.csv"'
--inform="file://D:\path    o\csv   emplate.csv"

问题在于 \ 这个符号表示特殊字符。如果你在字符串前面加上 "r" 这个字母,这些特殊字符就不会被转义了:

>>> print r'--inform="file://D:\path\to\csv\template.csv"'
--inform="file://D:\path\to\csv\template.csv"
1

在Windows系统上,你可以直接把命令作为字符串传递,也就是原样传递:

from subprocess import check_output

cmd = r'MediaInfo.exe --inform="file://D:\path\to\csv\template.csv" test.mp4'
out = check_output(cmd)

注意:r'' -- 这里用的是原始字符串字面量,这样可以避免把'\t'解释成一个制表符,而是把它当作两个字符(反斜杠和t)来处理。

另外,如果你设置了stdout=PIPE, stderr=PIPE,那么你需要同时读取这两个输出流,并且要在调用p.wait()之前完成,否则如果命令输出的内容太多,就可能会出现死锁的情况。


如果把命令作为字符串传递有效的话,你也可以尝试用列表作为参数:

from subprocess import check_output
from urllib import pathname2url

cmd = [app, '--inform']
cmd += ['file:' + pathname2url(r'D:\path\to\csv\template.csv')]
cmd += [filename]
out = check_output(cmd)

你能写个例子说明你提到的p.wait()死锁吗?

这很简单。只需要在子进程中产生大量输出:

import sys
from subprocess import Popen, PIPE

#XXX DO NOT USE, IT DEADLOCKS
p = Popen([sys.executable, "-c", "print('.' * (1 << 23))"], stdout=PIPE)
p.wait() # <-- this never returns unless the pipe buffer is larger than (1<<23)
assert 0 # unreachable

撰写回答