我有一个Python脚本,需要以root权限进行很多操作,比如在/etc中移动文件、使用apt-get安装等。我目前拥有的是:
if os.geteuid() != 0:
exit("You need to have root privileges to run this script.\nPlease try again, this time using 'sudo'. Exiting.")
这是做检查的最佳方式吗?还有其他最佳实践方法吗?
我有一个Python脚本,需要以root权限进行很多操作,比如在/etc中移动文件、使用apt-get安装等。我目前拥有的是:
if os.geteuid() != 0:
exit("You need to have root privileges to run this script.\nPlease try again, this time using 'sudo'. Exiting.")
这是做检查的最佳方式吗?还有其他最佳实践方法吗?
os.geteuid
可以获取有效用户ID,这正是您想要的,因此我无法想到更好的方法来执行此类检查。值得注意的是标题中的 "root-like" 一词还有一点不确定:您的代码仅检查 root
,没有任何 "like" 的内容,实际上我也不知道 "类似于 root 但不是 root" 是什么意思——因此,如果您的意思与 "exactly root" 不同,或许可以澄清一下,谢谢!
根据EAFP(宁愿请求原谅,而不是事先获得许可)原则:
import errno
try:
os.rename('/etc/foo', '/etc/bar')
except IOError as e:
if e[0] == errno.EPERM:
sys.exit("You need root permissions to do this, laterz!")
如果你担心 os.geteuid()
的不可移植性,那么你可能本来就不应该乱动 /etc
。import os, subprocess
def prompt_sudo():
ret = 0
if os.geteuid() != 0:
msg = "[sudo] password for %u:"
ret = subprocess.check_call("sudo -v -p '%s'" % msg, shell=True)
return ret
if prompt_sudo() != 0:
# the user wasn't authenticated as a sudoer, exit?
sudo -v
开关会更新用户缓存的凭证(详见 man sudo
)。对于Linux操作系统:
def is_root():
return os.geteuid() == 0
我喜欢在环境变量中检查sudo:
如果os.environ.keys()中没有'SUDO_UID',则: 打印"该程序需要超级用户权限。" sys.exit(1)
os.environ.keys()
中还有我想要的其他信息! - Brōtsyorfuzthrāx.keys()
,只需使用if not 'SUDO_UID' in os.environ:
即可。--谢谢! - kolimport os
def check_privileges():
if not os.environ.get("SUDO_UID") and os.geteuid() != 0:
raise PermissionError("You need to run this script with sudo or as root.")
SUDO_UID
在非使用 sudo
运行脚本时不可用。
if
的第二部分呢?检查SUDO_UID
的存在是否足够? - mike rodent(很抱歉评论框太小了)
Paul Hoffman,你是正确的,我只回答了涉及内在特性的一个问题部分,但如果它不能处理 apt-get
,那么它就不是一个值得信赖的脚本语言。首选的库有点冗长,但它可以完成工作:
>>> apt_get = ['/usr/bin/apt-get', 'install', 'python']
>>> p = subprocess.Popen(apt_get, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> p.wait()
100 # Houston, we have a problem.
>>> p.stderr.read()
'E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)'
'E: Unable to lock the administration directory (/var/lib/dpkg/), are you root?\n'
但是Popen
是一种通用工具,可以为了方便而进行包装:
$ cat apt.py
import errno
import subprocess
def get_install(package):
cmd = '/usr/bin/apt-get install'.split()
cmd.append(package)
output_kw = {'stdout': subprocess.PIPE, 'stderr': subprocess.PIPE}
p = subprocess.Popen(cmd, **output_kw)
status = p.wait()
error = p.stderr.read().lower()
if status and 'permission denied' in error:
raise OSError(errno.EACCES, 'Permission denied running apt-get')
# other conditions here as you require
$ python
>>> import apt
>>> apt.get_install('python')
Traceback ...
OSError: [Errno 13] Permission denied running apt-get
现在我们回到异常处理。我不想评论子进程模块类似于Java中的过度泛化。
我的应用程序使用以下代码:
import os
user = os.getenv("SUDO_USER")
if user is None:
print "This program need 'sudo'"
exit()
TypeError
,因为如果您不以 root 身份运行,则 os.getenv("SUDO_USER")
返回 None
,它是 NoneType
类型,您不能将 str
和 NoneType
连接起来。如果您想使用 os.getenv("SUDO_USER")
来解决问题,应该像这样做:
if os.getenv("SUDO_USER") == None: print "This program need 'sudo'"; exit()
- Or Bos.getenv('HOME')
的东西结合使用时,它将告诉您当前用户是root
还是sudo
,这通常是您的脚本需要知道的。 - Prahlad Yerisudo
和 sudo -E
对于 HOME
有不同的输出,而且两者都是 sudo。 - Pedro A这完全取决于您希望应用程序有多可移植。如果您是指业务,那么我们必须假设管理员帐户并不总是等于0。这意味着仅检查euid 0是不够的。问题在于,有些情况下,一个命令会表现得像您是root,而下一个命令将因权限被拒绝而失败(考虑SELinux和其他情况)。因此,最好优雅地失败,并在适当时检查EPERM errno。