Как исправить 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.

Рекомендации

  1. Cron не работает с подпроцессом python
  2. Как заставить Crontab запускать скрипт 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')
Другие вопросы по тегам