![](/img/trans.png)
[英]capture stderr from python subprocess.Popen(command, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
[英]Issue when combining pipe command and sudo with Python Subprocess
我正在尝试利用 Python 模块subprocess
在 Mac 上自动执行终端命令。 具体来说,我正在运行某个命令来在我的机器上创建端口映射。 但是,有问题的命令需要 root 权限和管道:
echo "
rdr pass inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080
" | sudo pfctl -ef -
为了使用subprocess
将我的 root 密码传递给 shell 命令,我按照此处找到的代码示例创建了以下脚本:
from subprocess import PIPE, Popen
p = Popen(['echo', '"rdr pass inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080"\n'], stdin=PIPE, stderr=PIPE, universal_newlines=True)
p2 = Popen(['sudo', '-S']+['pfctl', '-ef', '-'], stdin=p.stdout, stderr=PIPE, universal_newlines=True)
return p2.communicate('my_root_password\n')[1]
请注意,为了将echo
输出的管道传输到命令pfctl -ef -
我已经创建了两个Popen
对象,并将第一个对象的stdout
传递给了第二个的stdin
参数,如subprocess
docs 中所推荐的,并且我正在使用Popen.communicate
将 root 密码写入标准输入。
但是,我上面的脚本不起作用,因为在终端中仍然提示我输入我的 root 密码。 奇怪的是,当使用没有管道的命令时,我能够成功地将我的 root 密码写入 stdin,例如,在运行sudo pfctl -s nat
(以显示我当前的端口映射设置)时:
p = Popen(['sudo', '-S']+'pfctl -s nat'.split(), stdin=PIPE, stderr=PIPE, universal_newlines=True)
print(p.communicate('root_password\n')[1])
上面的代码有效,因为映射配置在没有任何密码提示的情况下显示。
如何更改我的第一个 Python 脚本,以便在我已经使用Popen.communicate
将密码写入标准输入后,不会提示我输入我的 root 密码?
我在 macOS Sierra 10.12.5 上运行此代码
我认为这只是管道未正确连接的一个简单案例。 您没有为第一个进程的stdout
指定管道,因此从外观上看,输出只是打印到终端然后进程完成。
当第二个进程开始时,它会提示输入密码,据我所知正确接收。 然而, communicate
方法然后关闭输入并等待进程完成。 据我所知,第一个进程的输出永远不会到达第二个进程,这就是您的脚本不起作用的原因。 而不是创建一个单独的echo
过程,为什么不给你需要的所有文本数据communicate
?
看起来您遇到的另一个问题(我没有要检查的 MAC)是sudo
将提示直接打印到终端(即通过/dev/tty
而不是stdout
)。 在我的sudo
版本(在 Debian 上)添加-S
选项会导致它打印提示到stderr
。 但是看起来-S
选项不会在 MAC 上执行此操作。 而是尝试使用-p ''
禁用提示。
把所有东西放在一起,这应该有效:
from subprocess import PIPE, Popen
from getpass import getpass
password = getpass()
cmd = ['sudo', '-k', '-S', '-p', '', 'pfctl', '-ef', '-']
p = Popen(cmd, stdin=PIPE, stderr=PIPE, universal_newlines=True)
text = password + '\n'
text += 'rdr pass inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080\n'
p.communicate(text)
此答案已更新为不使用纯文本密码。 请参阅下面的评论,了解为什么这是一个坏主意的一个很好的例子! 另请注意,使用 Python 在内存中存储密码并不完全安全,就像将内存交换到磁盘一样,这将包括纯文本形式的密码。 对于较低级别的语言,将使用mlock
系统调用来防止任何包含密码的内存被交换。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.