subprocess 应该如何用于具有 here-documents 和多个管道的命令?

How should subprocess be used for commands featuring here-documents and multiple pipes?

如何在 Bash 中使用 subprocess 而不是 os 到 运行 的命令如下?:

import os
text     = "~|||-:this is text:-|||~"
fileName = "sound.wav"
command  =\
    "IFS= read -d \'\' text <<EOF\n" +\
    text + "\n" +\
    "EOF\n" +\
    "echo \"${text}\" | sed -e 's/\([[:punct:]]\)//g' | text2wave -scale 1 -o " + fileName
os.system(command)

理想情况下,这将在 Bash 中评估为以下内容:

IFS= read -d '' text <<EOF
~|||-:this is text:-|||~
EOF
echo "${text}" | sed -e 's/\([[:punct:]]\)//g' | text2wave -scale 1 -o sound.wav

请注意,我在命令中同时使用了 here-document 和多个管道。我知道我不需要在命令中进行 sed 处理,但是我正在尝试专门查看这样的命令在 Bash 中如何使用 subprocess 运行 .

目前,我在subprocess命令程序中看到了一些'pipes'的实现,但与简单的竖线符号相比,这些实现非常冗长。我可以想象这种情况会因多个管道而变得噩梦般。至于这里的文档,我不知道如何用 subprocess 来实现它们。我会重视您可能拥有的有关实施此功能的任何指导。

程序 text2wave 是 Festival 的一部分,如果您有兴趣的话。

Here-docs 和管道 (|) 是 shell 的属性。如果你想运行字面上的命令,使用shell=True:

from subprocess import check_call

check_call(r"""IFS= read -d '' text <<EOF
~|||-:this is text:-|||~
EOF
echo "${text}" | sed -e 's/\([[:punct:]]\)//g' | text2wave -scale 1 -o sound.wav
""", shell=True)

一样,部分甚至全部命令都可以在Python中实现。

如果 shell 很适合您的问题,那么一定要使用 shell.

你有时想要将某些东西移植到 Python 的原因至少对我来说是出于更好的控制:你希望能够在(你的 shell 脚本是) 管道,或者你想在处理的中途保留结果,这在 shell 中很麻烦,因为管道是一维的。

如果您真的坚持,那么您提到(但不 link )的资源就是通常的做法;但由于上述原因,这并不是特别 "common".

这是一个不使用 shell 的例子,改编自 this question:

from subprocess import Popen, PIPE

input="""
~|||-:this is text:-|||~
"""
p1 = Popen(['sed', r's/\([[:punct:]]\)//g'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
p2 = Popen(['text2wave', '-scale', '1', '-o', fileName],
    stdin=p1.stdout, stdout=PIPE, stderr=PIPE)
p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
p1.stdin.write(input)
p1.stdin.close()
output, error = p2.communicate()
p1.wait()
print('status: {0}\nOutput: {1}\nError:{2}'.format(p2.returncode, output, error))

我确信这可以扩展到两个以上的子进程,但坦率地说,如果你真的需要弄清楚这一点,我也很确定你做错了。

... 而且,正如评论中已经指出的那样,sed 部分可以很容易地替换为 simple Python snippet;

from string import punctuation
input = input.translate(None, punctuation)

另请注意 Python 多行字符串如何替换此处的文档。

os.popen 演示: :

print os.popen(r"""
    /bin/bash<<EOF
shell line 1...
shell line 2...
shell line 3...
EOF
""").read()

subprocess.Popen("""
    /bin/bash<<EOF
shell line 1...
shell line 2...
shell line 3...
EOF
""", shell=True)