使用Python关闭计算机(Linux)

19
我正在尝试编写一个脚本,如果满足一些条件,就会使用命令关闭计算机。
os.system("poweroff")

也尝试了

os.system("shutdown now -h")

还有其他一些方法,但是当我运行它时,什么都没有发生,计算机会顺利执行代码,没有崩溃或产生任何错误信息,并正常终止脚本,而不关闭计算机。

如何使用Python关闭计算机?

编辑:似乎我尝试的命令需要管理员权限。有没有办法在脚本中关闭计算机而不需要提升权限?


3
“poweroff”和“shutdown”需要特权权限。你使用哪个用户来执行脚本? - fedorqui
我一直以“普通用户”的身份运行它...谢谢,我会编辑问题以反映该解决方案应在无root访问权限的情况下工作。 - user3522859
您无法使用普通用户权限关闭系统。您的最终目标是什么? - Joni
你也可以使用 sudo,但是你仍然需要通过 sudoers 获取权限。请注意,关闭计算机是一件应该限制给可信用户的事情,出于显而易见的原因。 - fedorqui
1
如果你的脚本还有其他不应该以特权运行的功能,你可能需要研究一下 polkit 或 sudo。如果你使用的发行版使用 systemd,则其 API 也可能对你有所帮助 - 默认情况下,它会尊重来自非特权用户的关机请求,如果他们是唯一登录的用户。无论如何,你总是至少需要从某些以特权运行的东西(systemd 和 polkit 是具有 dbus api 的长时间运行的特权进程,sudo 和 su 是 setuid root 二进制文件)中获得帮助,因为关机一个特权操作。 - lvc
1
好的,谢谢。最终目标是在完成耗时任务后使脚本关闭计算机,以防止过热;以sudo权限运行可以满足我的要求。 - user3522859
10个回答

27
import os
os.system("shutdown now -h")

以 root 权限执行您的脚本。


7
os.system("sudo shutdown now -h") 在我的电脑上运行成功了 ;-)。 - Anatoly Alekseev

22
许多 Linux 发行版要求具有超级用户权限才能执行 shutdownhalt,但是如果你正在使用计算机并想要关闭它,为什么不需要成为 root 用户呢?你只需打开菜单,点击 Shutdown,即可关机而无需成为 root 用户,对吧?
嗯...这背后的理论是:如果你可以物理接触计算机,那么你可以随时拔掉电源并将其关闭。因此,现在许多发行版允许通过访问可通过 dbus 访问的本地系统总线来关闭电源。问题是 dbus(或者说通过它公开的服务)在不断改变。我建议安装一个 dbus 查看工具,例如 D-feet(请注意:它仍然很难可视化,但可能有所帮助)。
请查看 这些 Dbus 关闭脚本
如果您的发行版中仍然有HAL(正在逐步废弃),请尝试以下操作:
import dbus
sys_bus = dbus.SystemBus()
hal_srvc = sys_bus.get_object('org.freedesktop.Hal',
                              '/org/freedesktop/Hal/devices/computer')
pwr_mgmt =  dbus.Interface(hal_srvc,
                'org.freedesktop.Hal.Device.SystemPowerManagement')
shutdown_method = pwr_mgmt.get_dbus_method("Shutdown")
shutdown_method()

这适用于Ubuntu 12.04(我刚刚关闭了我的计算机以确保它可以工作)。如果你使用的是更新的版本……那么,它可能不起作用。这种方法的缺点是:它非常依赖于特定的发行版。
你可能需要安装dbus-python包才能使其正常工作(http://dbus.freedesktop.org/doc/dbus-python/doc/tutorial.html)。 更新1: 我进行了一些研究,看起来在更新的Ubuntu版本中通过ConsoleKit实现。我已经在我的Ubuntu 12.04中测试了下面的代码(其中包含弃用的HAL和更新的ConsoleKit),它确实关闭了我的计算机:
>>> import dbus
>>> sys_bus = dbus.SystemBus()
>>> ck_srv = sys_bus.get_object('org.freedesktop.ConsoleKit',
                                '/org/freedesktop/ConsoleKit/Manager')
>>> ck_iface = dbus.Interface(ck_srv, 'org.freedesktop.ConsoleKit.Manager')
>>> stop_method = ck_iface.get_dbus_method("Stop")
>>> stop_method()

更新2:

也许不需要root权限就能做到这一点的原因值得更广泛的解释。让我们聚焦于较新的ConsoleKit(在我看来,HAL更为复杂混乱)。

ConsoleKit是在您的系统中以root身份运行的服务:

borrajax@borrajax:/tmp$ ps aux|grep console-kit
root 1590  0.0  0.0 1043056 3876 ? Sl   Dec05   0:00 /usr/sbin/console-kit-daemon --no-daemon

现在,d-bus只是一个消息传递系统。你有一个服务,比如ConsoleKit,它向d-bus公开一个接口。其中一个公开的方法是Stop(如上所示)。ConsoleKit的权限受到PolKit的控制,尽管基于常规Linux权限,但提供了更精细的控制"谁可以做什么"。例如,PolKit可以说:"如果用户已登录计算机,则允许他执行某些操作。如果是远程连接,则不允许。"如果PolKit确定您的用户被允许调用ConsoleKitStop方法,则该请求将通过(或通过d-bus传递给ConsoleKit(随后将关闭计算机,因为它可以...因为它值得...因为它是root)。

进一步阅读:

总结一下:您无法在没有root权限的情况下关闭计算机。但是,您可以告诉正在以root权限运行的服务来为您关闭系统。

更新3:

在2021年12月,原始答案撰写七年后,我不得不再次执行此操作。这次是在Ubuntu 18.04上执行。

毫不奇怪,事情似乎有了一些变化:

因此,我们仍然可以使用非特权脚本关闭计算机:

#! /usr/bin/python3
from pydbus import SystemBus
bus = SystemBus()

proxy = bus.get('org.freedesktop.login1', '/org/freedesktop/login1')
if proxy.CanPowerOff() == 'yes':
    proxy.PowerOff(False)  # False for 'NOT interactive'

更新3.1:

看起来它并不是我想象中的全新那么新鲜X-D

这个问题已经有@Roeften在同一个线程中给出了答案

额外奖励

我在你的评论中读到,你想在完成耗时任务后关闭计算机以防止过热... 你知道吗,你可以可能使用RTC在给定时间开机吗?(参见此处此处)相当酷,对吧?(当我发现我可以做到这一点时,我非常兴奋...):-D


3
@black: 你再说一遍?“familiar”是指不太严肃的意思吗?如果是这样,那是的。编程很有趣!而且令人兴奋!!!还很酷 :-) - Savir
1
我指的是DaveHax。别担心。 - edmz

9
最好的关机方式是使用以下代码
import os
os.system('systemctl poweroff') 

只有在使用systemd的情况下才能起作用。并非所有的Linux发行版都具备此功能。 - Michiel van Baak

3

有没有不需要提升权限就能关闭的方式?

没有(幸好没有!)。

请记住,您可以使用几个系统功能来使普通用户更容易进行特权升级:

  • sudo(超级用户运行命令)
  • setuid(设置用户ID)
  • setcap(设置文件能力)

3

补充@BorrajaX的回答,针对使用logind (新版本fedora系统)的用户:

import dbus
sys_bus = dbus.SystemBus()
lg = sys_bus.get_object('org.freedesktop.login1','/org/freedesktop/login1')
pwr_mgmt =  dbus.Interface(lg,'org.freedesktop.login1.Manager')
shutdown_method = pwr_mgmt.get_dbus_method("PowerOff")
shutdown_method(True)

2

linux:

import subprocess
cmdCommand = "shutdown -h now"
process = subprocess.Popen(cmdCommand.split(), stdout=subprocess.PIPE)

Windows:

import subprocess
cmdCommand = "shutdown -s"
process = subprocess.Popen(cmdCommand.split(), stdout=subprocess.PIPE)

2
import os
os.system("shutdown now -h")

Execution: sudo python_script.py


import subprocess
import shlex
cmd = shlex.split("sudo shutdown -h now")
subprocess.call(cmd)

执行: $ python_script.py # 不需要sudo权限

注:原文中的"Original Answer"翻译成中文后并没有被使用到,因此本次翻译未对其进行处理。


0

试一下这个

import os
os.system("sudo shutdown now -h")

这对我有用


-1

我正在使用Fedora,它对我来说很好用。我所需要做的就是在终端中输入这行命令:

$ sudo python  yourScript.py

-2

有一种方法可以在不使用提升的权限的情况下关闭计算机。

import os
subprocess.call(['osascript', '-e', 'tell app "system events" to shut down'])

osascript 不是 Linux。 - Stephane Martin
啊,抱歉我还是新手 :D - RyanKramer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接