Python subprocess.check_call 问题

0 投票
3 回答
961 浏览
提问于 2025-04-17 08:17

我知道我做错了什么。

在命令行里,我会输入:

cuebreakpoints cuefile.cue | shnsplit -o flac flacfile.flac

这样就可以根据cue文件来分割flac文件。因为我正在写一个小工具(用Python)来转换flac文件,所以我想把这部分代码放进我的程序里。

所以我用Python的方式写了:

for root, dirs, files in os.walk(args):
    ...
    cmd = ('cuebreakpoints', cue, '|', 'shnsplit', '-o', 'flac', flacs[0])
    subprocess.check_call(cmd, cwd=None)
    ....

这里的'cue'是指cue文件,而'flacs[0]'是指flac文件。但是我遇到了一个错误:

subprocess.CalledProcessError: 命令 '('cuebreakpoints', '41_30sec.cue', '|', 'shnsplit', '-o', 'flac', '41_30sec.flac')' 返回了非零的退出状态 1

是不是因为PIPE的原因导致的问题?

3 个回答

0

这里有个小提示。

在用 Python 写脚本的时候,如果需要使用子命令,我发现 shlex 这个工具特别有用。它可以帮助我们处理更复杂的命令,而不用太担心最终的命令列表会是什么样子。

import shlex

...
cmd = "cuebreakpoints '%s' | shnsplit -o flac '%s'" % (cue, flacs[0])
args = shlex.split(cmd)

subprocess.call(args ...)
2

如果你想使用一些像管道这样的命令行功能,你需要在调用 check_call 时加上 shell=True 这个参数,并且把命令写成一个完整的字符串:

check_call("cuebreakpoints '%s' | shnsplit -o flac '%s'" % (cue, flacs[0]),
           shell=True)

但是要注意,当你用未处理过的 cueflacs 时,使用 shell=True 可能会带来 安全隐患

2

为了避免将命令字符串传递给一个外壳程序(这样可以避免larsmans提到的安全问题),你可以创建两个 subprocess.Popen 对象,并将第一个对象的输出连接到第二个对象的输入(这基本上就是外壳程序为你做的事情):

关于如何做到这一点的例子,请查看文档中的 替代外壳管道 部分。

撰写回答