Python 子进程与 heredoc

5 投票
4 回答
4529 浏览
提问于 2025-04-15 14:03

我在玩Python的subprocess模块,尝试了一些例子,但我似乎无法让heredoc语句正常工作。

这是我正在尝试的一个简单例子:

import subprocess
a = "A String of Text"
p = subprocess.Popen(["cat", "<<DATA\n" + a + "\nDATA"])

当我运行上面的代码时,我得到了以下错误:

cat: <<DATA\nA String of Text\nDATA: No such file or directory

我是不是做错了?这真的可行吗?如果可以的话,我该怎么做呢?


更新

我想说的是,这种做法在真正的Python程序中是不应该使用的,因为有更好的方法来实现这个功能。

4 个回答

4

正如其他人提到的,你需要在一个命令行窗口中运行它。使用Popen这个工具时,加上一个参数shell=True就能很简单地做到这一点。我得到了以下输出:

>>> import subprocess
>>> a = "A String of Text"
>>> p = subprocess.Popen("cat <<DATA\n" + a + "\nDATA", shell=True)
>>> A String of Text

>>> p.wait()
0
4

你正在把一些 shell 语法当作参数传给 cat 程序。你可以试试这样做:

p = subprocess.Popen(["sh", "-c", "cat <<DATA\n" + a + "\nDATA"])

不过,这个想法本身就不太对。你应该使用 Python 的功能,而不是在你的 Python 脚本里调用 shell 脚本。

而且在这个特定的情况下,shell 的 heredoc 语法会把变量的值插入进去,所以你需要对 a 里面的所有文本进行转义,并确保里面没有 DATA 这一行。


如果用 Python 来实现,我觉得最接近的想法是(假设你不只是想用 print(a) 输出内容;-))把变量的值传给一个新进程的标准输入:

p = subprocess.Popen(["program", ...], stdin=subprocess.PIPE)
p.communicate(a)
6

Shell中的“heredoc”是一个功能,允许你在命令中直接写入多行文本。不过,subprocess.Popen默认情况下并不会通过shell来运行你的命令,所以这种写法是行不通的。

不过,既然你已经在使用管道了,就没必要再用shell的heredoc功能。你只需要把你的字符串a写入你刚启动的进程的标准输入管道就可以了。这其实和shell使用heredoc的方式是一样的。

你可以通过Popen.communicate()来实现这一点:

p.communicate(a)

communicate()函数的返回值包含了进程的输出(分为两个流,具体可以查看文档)。

撰写回答