从python脚本以超级用户身份运行命令

时间:2009-02-19 22:33:16

标签: python subprocess sudo

所以我试图让一个进程在使用子进程的python脚本中作为超级用户运行。在ipython shell中类似于

proc = subprocess.Popen('sudo apach2ctl restart',
                        shell=True, stdin=subprocess.PIPE,
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE)

工作正常,但只要我将其粘贴到脚本中,我就会开始:sudo: apach2ctl: command not found

我猜这是由于sudo处理ubuntu环境的方式。 (我也尝试了sudo -E apche2ctl restartsudo env path=$PATH apache2ctl restart无效)

所以我的问题基本上是,如果我想以超级用户身份运行apache2ctl restart,在需要时提示用户输入超级用户密码,我应该怎么做呢?我无意在脚本中存储密码。

编辑:

我尝试将命令作为字符串传递并标记为列表。在python解释器中,使用字符串我将正确地获得密码提示(仍然不像我原来的问题那样在python脚本中工作),列表只是给出了sudo的帮助屏幕。

编辑2:

所以我收集到的是,当shell = True时,Popen将使用一些命令作为字符串,需要

proc = subprocess.Popen(['sudo','/usr/sbin/apache2ctl','restart'])

没有'shell = True'让sudo工作。

谢谢!

8 个答案:

答案 0 :(得分:23)

尝试:

subprocess.call(['sudo', 'apach2ctl', 'restart'])

子进程需要访问真正的stdin / out / err才能提示你,并读入你的密码。如果将它们设置为管道,则需要自己将密码提供给该管道。

如果你没有定义它们,那么它会抓取sys.stdout等等......

答案 1 :(得分:14)

尝试提供apache2ctl的完整路径。

答案 2 :(得分:11)

另一种方法是让您的用户无密码sudo user

在命令行上键入以下内容:

sudo visudo

然后添加以下内容并用您的<username>替换:

<username> ALL=(ALL) NOPASSWD: ALL

这将允许用户执行sudo命令而无需询问密码(包括由该用户启动的应用程序。这可能存在安全风险

答案 3 :(得分:5)

你必须像这样使用Popen:

cmd = ['sudo', 'apache2ctl', 'restart']
proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

它需要一个列表。

答案 4 :(得分:4)

我将它用于python 3.5。我是使用 subprocess 模块完成的。使用这样的密码非常不安全

subprocess模块将命令作为字符串列表,因此要么事先使用 split()创建列表,要么稍后传递整个列表。阅读文档以获取更多信息。

我们在这里做的是回显密码,然后使用管道,我们通过&#39; -S&#39;将其传递给sudo。参数。

#!/usr/bin/env python
import subprocess

sudo_password = 'mysecretpass'
command = 'apach2ctl restart'
command = command.split()

cmd1 = subprocess.Popen(['echo',sudo_password], stdout=subprocess.PIPE)
cmd2 = subprocess.Popen(['sudo','-S'] + command, stdin=cmd1.stdout, stdout=subprocess.PIPE)

output = cmd2.stdout.read().decode() 

答案 5 :(得分:2)

我尝试了所有解决方案,但没有奏效。想要使用Celery运行长时间运行的任务,但是对于这些我需要使用subprocess.call()运行sudo chown命令。

这对我有用:

要添加安全环境变量,请在命令行中键入:

export MY_SUDO_PASS="user_password_here"

测试它是否正常工作:

echo $MY_SUDO_PASS
 > user_password_here

要在系统启动时运行它,请将其添加到此文件的末尾:

nano ~/.bashrc  
#.bashrc
...
existing_content:

  elif [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
  fi
fi
...

export MY_SUDO_PASS="user_password_here"

您可以稍后在此处添加所有环境变量密码,用户名,主机等。

如果你的变量准备就绪,你可以运行:

更新:

echo $MY_SUDO_PASS | sudo -S apt-get update

或安装Midnight Commander

echo $MY_SUDO_PASS | sudo -S apt-get install mc

用sudo启动Midnight Commander

echo $MY_SUDO_PASS | sudo -S mc

或者从python shell(或Django / Celery),以递归方式更改目录所有权:

python
>> import subprocess
>> subprocess.call('echo $MY_SUDO_PASS | sudo -S chown -R username_here /home/username_here/folder_to_change_ownership_recursivley', shell=True)

希望它有所帮助。

答案 6 :(得分:1)

要以root用户身份运行命令并在命令提示符处传递密码,您可以这样做:

import subprocess
from getpass import getpass

ls = "sudo -S ls -al".split()
cmd = subprocess.run(
    ls, stdout=subprocess.PIPE, input=getpass("password: "), encoding="ascii",
)
print(cmd.stdout)

例如,可能是这样的:

import subprocess
from getpass import getpass

restart_apache = "sudo /usr/sbin/apache2ctl restart".split()
proc = subprocess.run(
    restart_apache,
    stdout=subprocess.PIPE,
    input=getpass("password: "),
    encoding="ascii",
)

答案 7 :(得分:0)

最安全的方法是事先提示输入密码,然后将其输入命令。提示输入密码将避免将密码保存在代码中的任何位置,并且也不会显示在bash历史记录中。这是一个示例:

from getpass import getpass
from subprocess import Popen, PIPE

password = getpass("Please enter your password: ")
# sudo requires the flag '-S' in order to take input from stdin
proc = Popen("sudo -S apach2ctl restart".split(), stdin=PIPE, stdout=PIPE, stderr=PIPE)
# Popen only accepts byte-arrays so you must encode the string
proc.communicate(password.encode())
相关问题