Как исправить wmctrl Не удается открыть отображение, когда Python открывает подпроцесс
Это моя программа, и она работает очень хорошо.
import subprocess
result = subprocess.check_output("wmctrl -l",shell=True,stderr=subprocess.STDOUT)
result = result.decode('UTF-8')
print(result)
Выход:
0x03800003 -1 name-PC Desktop
0x03e00037 0 name-PC How to fix wmctrl Cannot open display when Python open subprocess - Stack
Overflow - Firefox
0x05000006 0 name-PC name@name-PC: ~
0x05a00001 0 name-PC pr.py — ~/Program — Atom
0x05001c85 0 name-PC Terminal
Но если я хочу запустить эту программу при запуске с правами root в Linux Mint, у меня проблемы. Я хочу запустить этот файл py при запуске как root, но я не знаю, как это сделать. Главный вопрос - как это сделать.
Это моя попытка решить проблему. Это не работает.
Я добавил файл pr.service
в папку /etc/systemd/system/
:
[Unit]
After=network.target
[Service]
ExecStart=/usr/local/bin/pr.sh
[Install]
WantedBy=default.target
Я создал файл pr.sh в папке /usr/local/bin/
:
#!/bin/bash
/usr/bin/python3 '/home/name/Program/pr.py'
Я использовал эти команды:
sudo chmod 744 /usr/local/bin/pr.sh
sudo chmod 664 /etc/systemd/system/pr.service
sudo systemctl daemon-reload
sudo systemctl enable pr.service
Если я запускаю свою программу с командой
systemctl start pr.service
Я вижу эту ошибку с командой
sudo journalctl -u pr.service
У меня есть ошибка команда subprocess.CalledProcess Ошибка: Команда 'wmctrl -l' вернула ненулевой статус выхода 1.
Я могу изменить свой файл py, например, я могу запустить
result = subprocess.check_output("/usr/bin/wmctrl -l",shell=True,stderr=subprocess.STDOUT)
Я могу изменить свой py-файл, чтобы увидеть ошибку:
import subprocess
try:
result = subprocess.check_output("/usr/bin/wmctrl -l -p",shell=True,stderr=subprocess.STDOUT)
result = result.decode('UTF-8')
except subprocess.CalledProcessError as e:
raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output))
print(result)
RuntimeError: команда '/usr/bin/wmctrl -l -p' возвращает с ошибкой (код 1): b'Не открыть дисплей.
Я читал об этой попытке найти решение: https://linuxconfig.org/how-to-automatically-execute-shell-script-at-startup-boot-on-systemd-linux
Это статья о том, как автоматически запускать скрипт в Linux от имени пользователя root. Я сделал эти вещи.
Моя главная цель - автоматически запустить мою программу с правами root:
import subprocess
try:
result = subprocess.check_output("/usr/bin/wmctrl -l -p",shell=True,stderr=subprocess.STDOUT)
result = result.decode('UTF-8')
except subprocess.CalledProcessError as e:
raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output))
print(result)
Вам не нужно находить ошибку в моем решении. Будет интересно найти любое решение.
3 ответа
Я сам нашел решение. Ключ должен использовать две команды:
os.system("xhost local:root &>/dev/null")
разрешить открытие корня X windows. А также
subprocess.check_output([command], shell=True, stderr=subprocess.STDOUT).decode('UTF-8')
command = "env DISPLAY=:0 XAUTHORITY=/home/ourname/.Xauthority "+"wmctrl -l -p -lp"
разрешить root читать наши настройки.
Таким образом, мы можем переписать нашу программу.
import subprocess
import gc
import time
prf = ["env", "DISPLAY=:0", "XAUTHORITY=/home/ourname/.Xauthority"]
while True:
r1 = subprocess.run(['xhost', 'local:root'],stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL )
r2 = subprocess.run([prf[0], prf[1], prf[2],"wmctrl", "-l", "-p", "-lp"], encoding='utf-8', stdout=subprocess.PIPE)
if r1.returncode == 0 and r1.returncode == 0:
print("Now we will not have problem with display error")
break
time.sleep(3)
while True:
r1 = subprocess.run([prf[0], prf[1], prf[2],"wmctrl", "-l", "-p", "-lp"], encoding='utf-8', stdout=subprocess.PIPE)
for line in r1.stdout.split('\n'):
print(line)
time.sleep(3)
gc.collect()
Это ошибка, которую я получал в Ubuntu 22.04. Я пытался использовать cron для запуска скрипта Python.
Cannot open display.
Traceback (most recent call last):
File "/home/usera/Applications/auto_close_old_nautilus_windows.py", line 55, in <module>
wlist1 = [l.strip() for l in get(["wmctrl", "-lp"]).splitlines() if nautpid in l]
AttributeError: 'NoneType' object has no attribute 'splitlines'
Эти 2 решения сработали для меня.
Решение 1
Бегать
crontab -e
Использоватьexport
экспортироватьDISPLAY
иXAUTHORITY
переменные. Обратите внимание, что перед символом равенства требуется обратная косая черта (XAUTHORITY\=
).
# /tmp/crontab.kCWtBN/crontab
# Edit this file to introduce tasks to be run by cron.
#
# [...]
# m h dom mon dow command
*/1 * * * * export DISPLAY=:1 && export XAUTHORITY\=/run/user/1000/gdm/Xauthority && python3 /home/usera/Applications/auto_close_old_nautilus_windows.py >>/home/usera/Applications/script.log 2>>/hom>
CTRL+X
иY
чтобы сохранить изменения.
Это должно работать. Ниже показано, что было у моего скрипта Python.
# auto_close_old_nautilus_windows.py - Note I do not pass in env=
subprocess.check_output(cmd).decode("utf-8").strip()
Решение 2
В вашем скрипте Python укажите переменные DISPLAY и XAUTHORITY и передайте их с аргументом env.
env = dict(DISPLAY = ':1', XAUTHORITY = f'/run/user/1000/gdm/Xauthority')
subprocess.check_output(cmd, env=env).decode("utf-8").strip()
Как были получены переменные DISPLAY и XAUTHORITY?
Добавьте эти 2 строки (os.environ.get) в свой скрипт.
# auto_close_old_nautilus_windows.py
# ...
# other code in script
print(os.environ.get("DISPLAY"))
print(os.environ.get("XAUTHORITY"))
# other code in script
# ...
Запустите свой скрипт.
python3 auto_close_old_nautilus_windows.py
Скрипт работает, и вы получаете этот вывод.
:1
/run/user/1000/gdm/Xauthority
Переменная DISPLAY:1
и XAUTHORITY/run/user/1000/gdm/Xauthority
. Ваш результат будет другим.
Почему ошибка возникает с самого начала?
Когда cron выполняет ваш скрипт, DISPLAY и XAUTHORITY не устанавливаются. Два решения, которые я упоминаю, настраивают DISPLAY и XAUTHORITY до того, как cron выполнит ваш скрипт Python.
Рекомендации
Ошибка "Не удается открыть дисплей". также доставил мне неприятности. Вот как я мог решить это в Linux Mint 20.3 - только код DISPLAY должен отличаться от ответа @ddd777. Часть xhost была не нужна.
user = 'yourusername'
env = dict(DISPLAY = ':0.0', XAUTHORITY = f'/home/{user}/.Xauthority')
def get(cmd):
return subprocess.check_output(['/bin/bash', '-c', cmd], env=env
).decode('utf-8')