简述:
L3viathan的回答 存在语法错误 编辑:在Python 3.5+上可以正常工作。这是适用于Python 3.4.3(默认分发于Ubuntu 16.04及以下版本)的版本:
if os.geteuid() == 0:
else:
subprocess.call(['sudo', 'python3'] + sys.argv)
但是,在我的使用案例中,我选择了不同的方法,因为它使得周围的代码更简单:
if os.geteuid() != 0:
os.execvp('sudo', ['sudo', 'python3'] + sys.argv)
说明
L3viathan的回答依赖于PEP 448,该规范被包括在Python 3.5中,并引入了额外的上下文,使得星号参数展开在更多情况下被允许。对于Python 3.4及以下版本,可以使用列表连接来达到相同的效果:
import os
import sys
import subprocess
if os.geteuid() == 0:
print("We're root!")
else:
print("We're not root.")
subprocess.call(['sudo', 'python3'] + sys.argv)
但请注意:
subprocess.call()
会启动一个子进程,这意味着在root完成运行脚本后,原始用户将继续运行他们的脚本。这意味着您需要将升级逻辑放在
if/else
块的一侧,以便在原始脚本完成时,它不会尝试运行任何需要提权的逻辑(L3viathan的示例就是如此)。
这并不一定是坏事 - 它意味着普通/升级的逻辑可以写在同一个脚本中并且可以很好地分离 - 但我的任务要求所有逻辑都需要以root权限运行。如果另一个块将为空,我不想浪费缩进级别,而且我没有意识到使用子进程会影响事情,所以我尝试了这个:
import os
import sys
import subprocess
if os.geteuid() != 0:
subprocess.call(['sudo', 'python3'] + sys.argv)
当然,它(指程序)崩溃了,因为在 root 完成后,常规用户恢复执行其脚本并尝试运行需要 root 权限的语句。
后来我发现了这个Gist,它推荐使用os.execvp()
- 它会替换正在运行的进程而不是启动一个子进程:
import os
import sys
if os.geteuid() != 0:
os.execvp('sudo', ['sudo', 'python3'] + sys.argv)
这似乎表现如预期,节省了一个缩进级别和3行代码。
注意:十分钟前我还不知道os.execvp()
,并且还不了解其使用可能存在的陷阱或细微差别。你的情况可能会有所不同。
sudo python myscript.py
- Robᵩexcept IOError as e: sys.stderr.write('Error: Failed to open file %s: %s' % (filename,str(e)))
- Jean-François Fabre