我肯定有一个盲点,但我找不到它是什么。
我编写了一个小型 Python 脚本,用于从声音菜单中删除 VLC。无论我从终端、启动器还是您能想到的任何方式运行它,它都能完美运行。
脚本实际上做了什么无非就是获取当前的设置:
gsettings get com.canonical.indicator.sound interested-media-players
编辑列表,并通过以下方式设置更改后的列表:
gsettings set com.canonical.indicator.sound interested-media-players "['newlist']"
这些命令由 Python 脚本执行。然而,从 cronjob 运行时( crontab -e
) 仅限 gsettings- 得到 -部分工作正常,但是不是gsettings (设置)- 放 -部分。得到部分与 cron 配合良好,我通过让脚本将数据(原始数据和编辑数据)写入外部文件进行了检查。
不是 Python 问题
为了查看问题是否与 Python 代码有关,我创建了一个应用更改后的声音菜单项列表的 bash 脚本。故事是一样的:bash 脚本从命令行或启动器运行良好,不是来自 cron,而同一脚本中的任何其他命令都可以正常运行。此外,如果我在下面的脚本末尾添加任何命令,它都可以正常工作,并且看起来脚本对自己的工作很满意。
为什么 gsettings放从 cron 启动时命令不起作用?
这是脚本:
#!/usr/bin/python3
import subprocess
def read_soundmenu():
# read the current launcher contents
get_menuitems = subprocess.Popen([
"gsettings", "get", "com.canonical.indicator.sound", "interested-media-players"
], stdout=subprocess.PIPE)
return eval((get_menuitems.communicate()[0].decode("utf-8")))
def set_current_menu(current_list): # this takes no effect from cron
# preparing subprocess command string
current_list = str(current_list).replace(", ", ",")
subprocess.Popen([
"gsettings", "set", "com.canonical.indicator.sound", "interested-media-players",
current_list,
])
current_list = read_soundmenu()
for item in current_list:
if item == "vlc.desktop":
current_list.remove(item)
set_current_menu(current_list)
答案1
解决方案
原来盲点是我知识上的一个漏洞。不跑步的原因具体的python 脚本(gsettings set
)中的命令是因为 cron 使用了一组非常受限制的环境变量。
要从 cron运行gsettings *set*
命令(一般来说),不仅仅需要从个人 cron 文件运行它;环境变量DBUS_SESSION_BUS_ADDRESS是正确执行所必需的。
为了方便和灵活,我根据以下信息解决了这个问题:这篇关于 stack overflow 的帖子,通过创建一个“中间”脚本,该脚本既导出变量又调用实际脚本。实际脚本编辑gsettings
。由于(通常)进程继承了其父进程的环境,因此现在脚本可以正常运行。
#!/bin/bash
PID=$(pgrep gnome-session)
export DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$PID/environ|cut -d= -f2-);/path/to/script.py
(假设 script.py 是可执行的)
在 Python 脚本中包含 DBUS_SESSION_BUS_ADDRESS 变量
为了能够通过 cron 运行的 Python 脚本进行编辑gsettings
(并且不需要中间脚本),可以将以下函数包含在脚本中。它应该gsettings set
在脚本中的函数之前调用。
#!/usr/bin/env python3
import os
import subprocess
def set_envir():
pid = subprocess.check_output(["pgrep", "gnome-session"]).decode("utf-8").strip()
cmd = "grep -z DBUS_SESSION_BUS_ADDRESS /proc/"+pid+"/environ|cut -d= -f2-"
os.environ["DBUS_SESSION_BUS_ADDRESS"] = subprocess.check_output(
['/bin/bash', '-c', cmd]).decode("utf-8").strip().replace("\0", "")