首页 > 解决方案 > 无法使用 Subprocess 模块成功解析和运行长命令

问题描述

我正在尝试通过在 Mac 上的终端中运行一系列命令来在我的机器上实现端口转发,这些命令可以在此处找到。我正在尝试通过subprocess在 Python 中使用来运行后一个链接中列出的端口映射命令。

我试图运行的命令subprocess是:

echo "
rdr pass inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080
" | sudo pfctl -ef -

我对上述命令的 Python 实现:

from subprocess import Popen, PIPE
commands = ['echo', '"rdr pass inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080"\n', '|', 'sudo', 'pfctl', '-ef', '-']
p = Popen(['sudo', '-S']+commands, stdin=PIPE, stderr=PIPE, universal_newlines=True)
print(p.communicate('root_password\n')[1])#be able to read password for sudo from stdin

但是,这个 Python 脚本不起作用,因为当我运行sudo pfctl -s nat以在我的机器上显示所有端口转发规则时,我的预期输出

rdr pass inet proto tcp from any to any port = 80 -> 127.0.0.1 port 8080

不显示到外壳。

然而,运行

echo "
rdr pass inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080
" | sudo pfctl -ef -

确实产生

rdr pass inet proto tcp from any to any port = 80 -> 127.0.0.1 port 8080

运行显示命令后sudo pfctl -s nat

如何subprocess改进我的实现以便正确输出规则列表?

编辑:奇怪的是,我可以sudo pfctl -s nat使用运行显示命令subprocess

p = Popen(['sudo', '-S']+'pfctl -s nat'.split(), stdin=PIPE, stderr=PIPE, universal_newlines=True)
print(p.communicate(f'myrootpassword\n')[1]))

sudo pfctl -s nat实现与在 shell 本身中运行时相同的输出。


我正在 macOS Sierra 10.12.5 上运行命令和 Python 尝试。

标签: pythonsubprocess

解决方案


您正在尝试使用Popen()执行多个命令的管道,但它不起作用。这是一个外壳功能。

我相信您需要Popen()多次调用,每个命令一次,并明确地将它们的标准输入/标准输出相互挂钩。


推荐阅读