Je dois avoir un angle mort, mais je ne trouve pas ce que c'est.
J'ai créé un petit script python qui supprime VLC du menu des sons. Il fonctionne parfaitement de quelque manière que ce soit que je l'utilise depuis le terminal, un lanceur ou tout ce que vous pouvez imaginer.
Ce que fait réellement le script n’est rien d’autre que l’obtenir les paramètres actuels:
gsettings get com.canonical.indicator.sound interested-media-players
éditez la liste et définissez la liste modifiée comme suit:
gsettings set com.canonical.indicator.sound interested-media-players "['newlist']"
Ces commandes sont exécutées par un script python. Cependant, lorsqu’il est exécuté depuis un cronjob (crontab -e
) uniquement les gsettings - get - une partie fonctionne, mais pas les gsettings - set - section. Que la section get fonctionne bien avec cron, j'ai vérifié en faisant en sorte que le script écrive les données (l'original ainsi que le fichier modifié) dans un fichier externe.
pas un python problème
Pour voir si le problème est lié au code python, j'ai créé un script bash qui applique une liste d'éléments de menu audio modifiée. L'histoire est la même: le script bash fonctionne correctement à partir de la ligne de commande ou d'un programme de lancement, et non à partir de cron, alors que toute autre commande du même script courir bien. De plus, si j'ajoute une commande à la fin du script ci-dessous, cela fonctionne bien et il semble que le script soit satisfait de son propre travail.
Pourquoi la commande gsettings set ne fonctionne-t-elle pas lorsqu'elle est lancée à partir de cron?
Voici le script:
#!/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)
La solution
Il s'est avéré que l'angle mort était un trou dans mes connaissances. La raison de ne pas exécuter des commandes spécifiques dans le script python (gsettings set
) était due au fait que cron utilise un ensemble très restreint de variables d'environnement.
Pour exécuter une commande gsettings *set*
de cron (en général), il ne suffit pas de l'exécuter à partir de votre fichier cron personnel; la variable d'environnement DBUS_SESSION_BUS_ADDRESS est nécessaire pour une exécution correcte.
Pour des raisons de commodité et de flexibilité, je l'ai résolu, inspiré par - et basé sur les informations contenues dans ce message sur le dépassement de pile , en créant un script "intermédiaire" qui exporte la variable et appelle le script lui-même. . Le script actuel édite gsettings
. Étant donné que (normalement) un processus hérite de l'environnement de son parent, le script s'exécute correctement.
#!/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
(en supposant que script.py est exécutable)
Incluant la variable DBUS_SESSION_BUS_ADDRESS dans un script python
Pour permettre l'édition gsettings
à l'aide d'un script python, exécuté par cron (et rendant inutile un script intermédiaire), la fonction ci-dessous pourrait être incluse dans le script. Il doit être appelé avant la fonction gsettings set
dans le script.
#!/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", "")