Как программно найти текущее значение DISPLAY, когда DISPLAY не установлен? (для использования в crontab)
У меня есть скрипт, который запускается через cron для смены обоев рабочего стола. Я могу заставить его работать, экспортируя переменную DISPLAY.
Но проблема меня беспокоит, что скрипт должен работать на всех системах. Как найти значение DISPLAY, установленное X-сервером, без использования $DISPLAY?
Итак, как я могу найти правильное значение для DISPLAY
программно. Я могу заставить его работать только тогда, когда DISPLAY=:1
, Установка его в ":0"
завершает работу скрипта с
No protocol specified
Cannot open display.
3 ответа
Вы не можете точно. Вы должны сделать предположения.
Притворись, что ты cron
и на секунду вы столкнулись с наихудшим сценарием: в систему вошли несколько пользователей, и каждый пользователь запускает несколько X-сеансов. Вы должны будете угадать пользователя (достаточно просто, мы выполняем его crontab) и один из сеансов X этого пользователя.
Если мы хотим предположить, что пользователь запускает один и только один сеанс X из tty, и получить этот сеанс $DISPLAY
значение, которое мы можем использовать w
:
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
user tty1 16:32 7:15 0.21s 0.19s -zsh
user tty2 :1 15:52 48:13 2:17 0.08s /sbin/upstart
user pts/3 :1 16:19 0.00s 0.66s 0.00s w
Например, здесь я вошел на tty1, tty2 (где я запускаю сеанс X) и на pts/3 (терминал, с которого я запускаю команду).
С небольшим разбором:
% w $(id -un) | awk 'NF > 7 && $2 ~ /tty[0-9]+/ {print $3; exit}'
:1
Итак, предполагая все вышесказанное:
0 0 * * * DISPLAY=$(w $(id -un) | awk 'NF > 7 && $2 ~ /tty[0-9]+/ {print $3; exit}') command
Сделаю cron
выполнять command
с $DISPLAY
установить первый сеанс X, запущенный в tty $DISPLAY
найденное значение для пользователя.
Более подробное обсуждение см. По https://unix.stackexchange.com/questions/17255/is-there-a-command-to-list-all-open-displays-on-a-machine
Я просто перечислю соответствующую информацию из этого ответа здесь:
Кажется, есть два простых способа найти экземпляры X-сервера, работающие в вашей системе.
w
:w
Команда выводит список всех открытых дисплеев. Вы можете использоватьawk
отфильтровать нужную вам информацию. Значения подFROM
значения, соответствующиеDISPLAY
,ashhar@xenon:[/tmp/.X11-unix] $ w 21:18:24 up 3:39, 4 users, load average: 0.31, 0.27, 0.30 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT ashhar tty2 :1 17:40 3:39m 6:11 0.08s /usr/bin/dunst ashhar pts/0 :1 17:41 3:36m 0.13s 0.05s vim .i3/config ashhar pts/1 :1 18:07 0.00s 1.44s 0.00s w ashhar pts/2 :1 18:15 9:59 0.79s 0.79s bash
Локальные дисплеи соответствуют розетке в
/tmp/.X11-unix
так что мы можем просто сделать:cd /tmp/.X11-unix && for x in X*; do echo ":${x#X}"; done
Вдохновленный ответом Ашхара Хасана, я бы использовал (протестировано на Ubuntu 23.04):
export DISPLAY=$(
find /tmp/.X11-unix/ -user $USER -type s -printf "%f" -quit | tr X :
)
Благодаря фильтрации по UID он будет работать даже при наличии нескольких вошедших в систему пользователей.
У меня есть сценарий X11wrap.sh, который позволяет мне запускать приложение X11 из системных сценариев, cron и т. д.
#!/bin/sh
set -eu
export DISPLAY=$(
find /tmp/.X11-unix/ -user $USER -type s -printf "%f" -quit | tr X :
)
# For applications that additionally require DBUS.
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u)/bus
exec "$@"
С его помощью я могу выдать следующий пример, и он правильно настроит систему X11:
echo X11wrap.sh xeyes | at now