使用Python关机Linux电脑
我正在尝试写一个脚本,如果满足一些条件,就让电脑关机。
os.system("poweroff")
我还试过
os.system("shutdown now -h")
还有其他一些方法。但是当我运行这些代码时,电脑只是按照代码执行,没有崩溃,也没有出现任何错误信息,最后正常结束了脚本,但电脑并没有关机。
请问怎么用Python让电脑关机呢?
补充说明:看起来我尝试的命令需要管理员权限。有办法在不提升权限的情况下从脚本中关机吗?
10 个回答
我只是想补充一下@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)
关闭系统的最佳方法是使用以下代码
import os
os.system('systemctl poweroff')
import os
os.system("shutdown now -h")
用管理员权限来运行你的脚本。
很多Linux系统在执行shutdown
或halt
命令时需要超级用户权限,但如果你坐在电脑前,为什么可以直接关机而不需要成为root
呢?你只需打开菜单,点击关机,电脑就关掉了,对吧?
其实,这背后的原因是,如果你能物理接触到电脑,比如直接拔掉电源线,那你就可以随意关机。因此,现在很多Linux系统允许通过本地系统总线来关机,这个总线可以通过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判断你的用户可以调用ConsoleKit的Stop
方法,那么这个请求就会通过d-bus
传递给ConsoleKit(它随后会关掉你的电脑,因为它有这个权限……因为它是root
)。
进一步阅读:
总结一下:你不能在不成为root
的情况下关掉电脑,但你可以告诉一个以root
身份运行的服务来为你关机。
更新 3:
在2021年12月,原答案发布七年后,我又需要做这个。这次是在Ubuntu 18.04上。
不出所料,情况似乎有些变化:
- 关机功能似乎是通过一个新的
org.freedesktop.login1
服务来处理的,这个服务是“新”的(咳咳!)SystemD机制的一部分。 dbus
的Python包似乎已经被弃用或被认为是“遗留”的。不过,有一个新的PyDbus库可以替代。
所以我们仍然可以用一个没有特权的脚本来关掉机器:
#! /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