我试图利用Python模块subprocess
在Mac上自动执行终端命令。具体来说,我正在运行一个certain command在我的机器上创建port mappings。但是,该命令需要root权限和管道:
echo "
rdr pass inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080
" | sudo pfctl -ef -
为了使用subprocess
将根密码传递给shell命令,我按照找到的代码示例here创建以下脚本:
注意,为了实现echo
输出到命令pfctl -ef -
的管道,我创建了两个Popen
对象,并按照^{stdout
传递给第二个对象的stdin
参数,并使用Popen.communicate
将根密码写入stdin。在
但是,我上面的脚本不起作用,因为终端仍然提示我输入根密码。奇怪的是,当使用不带管道的命令时,例如,当运行sudo pfctl -s nat
(显示我当前的端口映射设置)时,我能够成功地将根密码写入stdin:
p = Popen(['sudo', '-S']+'pfctl -s nat'.split(), stdin=PIPE, stderr=PIPE, universal_newlines=True)
print(p.communicate('root_password\n')[1])
上面的代码可以工作,因为映射配置显示时没有任何密码提示。在
在已经使用Popen.communicate
将密码写入stdin之后,如何更改我的第一个Python脚本,从而不提示我输入根密码?在
我在macOS Sierra 10.12.5上运行此代码
我想这只是一个简单的管道连接不好的例子。您没有为第一个进程的
stdout
指定一个管道,因此从外观来看,输出只是打印到终端,然后进程就结束了。在当第二个进程开始时,它将提示输入密码,据我所知,它将正确接收它。但是,
communicate
方法随后关闭输入并等待进程完成。据我所知,第一个进程的输出永远不会到达第二个进程,这就是为什么您的脚本不能工作。与其创建一个单独的echo
进程,不如用communicate
发送所需的所有文本数据?在另一个问题是}。在我的
sudo
直接将提示打印到终端(即通过/dev/tty
而不是stdout
),而不是{sudo
(在Debian上)版本中,添加-S
选项会导致它将提示打印到stderr
。不过,在MAC上,-S
选项似乎不能做到这一点。请尝试使用-p ''
禁用提示。在把所有的东西放在一起,这应该是可行的:
安全说明
此答案已更新为不使用纯文本密码。请参阅下面的评论,了解为什么这是一个坏主意的好例子!还请注意,使用Python在内存中存储密码并不完全安全,就像将内存交换到磁盘一样,这将包括明文形式的密码。在较低级别的语言中,
mlock
系统调用将用于防止任何包含密码的内存被交换。在相关问题 更多 >
编程相关推荐