Представьте: вы настроили идеальный скрипт для мониторинга диска, который должен показывать результаты в отдельном окне терминала. Вручную всё работает как часы, но при запуске через cron – тишина. Проблема кроется в тонкостях взаимодействия cron с графической средой, и сейчас мы разберёмся, как заставить их работать в паре.
Почему cron «не видит» ваш дисплей
Когда вы запускаете команду вручную, система автоматически подставляет переменные окружения – включая DISPLAY=:0
, которая указывает на основной X-сервер (тот самый, куда выводится ваш рабочий стол). Но cron работает в изолированном окружении без доступа к этим настройкам.
Вот что происходит под капотом:
- Cron – демон, работающий вне пользовательской сессии (даже если задача добавлена через
crontab -e
) - Графические приложения в Linux требуют:
– Адрес X-сервера (DISPLAY)
– Права доступа (обычно хранятся в ~/.Xauthority) - Без этих параметров xterm просто не знает, куда выводить окно
Проверьте сами: выполните
env | grep DISPLAY
в терминале и сравните с выводом cron-задачи, где первая команда –env > /tmp/cron_env.log
.
DISPLAY=:0 – магия или логика?
Вот типичная ошибка в настройке:
# Не работает в cron:
xterm -e 'your_script.sh'
# Рабочий вариант:
DISPLAY=:0 xterm -e 'your_script.sh'
Что на самом деле делает DISPLAY=:0:
- Указывает на первый запущенный X-сервер (обычно основной дисплей)
- Имеет формат
hostname:display_number.screen_number
- Локальный сервер сокращается до :0 (эквивалент :0.0)
Но есть нюанс — в некоторых сценариях:
- DISPLAY может быть :1, если вы вошли через второй сеанс
- На серверах без графической оболочки переменная вообще отсутствует
- Wayland использует другой синтаксис (WAYLAND_DISPLAY=wayland-0)
Ситуация | Значение DISPLAY |
Стандартный десктоп | :0 |
Второй X-сервер | :1 |
Запуск из SSH-сессии | Не задано |
Надёжные способы указать DISPLAY для cron
Способ 1 – жёсткое задание в crontab (подходит для простых случаев):
# В начале файла crontab:
DISPLAY=:0
XAUTHORITY=/home/user/.Xauthority
# Затем ваши задачи:
* * * * * xterm -e 'echo "Работает!"'
Способ 2 – динамическое определение DISPLAY (рекомендуется):
1. Создайте скрипт для сохранения текущих настроек:
#!/bin/bash
echo "export DISPLAY=$(loginctl list-sessions | grep $(id -u) | awk '{print $3}')" > ~/.current_display
echo "export XAUTHORITY=$HOME/.Xauthority" >> ~/.current_display
2. Добавьте его в автозагрузку (через ~/.config/autostart/ или systemd)
3. В cron-задаче:
* * * * * source ~/.current_display && xterm -e 'your_script'
Кстати, если используете Wayland (как в Ubuntu 22.04+), вместо DISPLAY потребуется задать WAYLAND_DISPLAY. Проверить текущий протокол можно командой
echo $XDG_SESSION_TYPE
.
Способ 3 – через systemd (современная альтернатива cron):
# Создайте сервисный файл
systemctl --user edit --force --full my-xterm.service
[Service]
Environment="DISPLAY=:0"
ExecStart=/usr/bin/xterm -e '/path/to/script.sh'
# Таймер для запуска каждые 5 минут
systemctl --user edit --force --full my-xterm.timer
[Timer]
OnCalendar=*:0/5
Частые ошибки
- Путь к .Xauthority без учёта домашней директории (используйте $HOME)
- Попытка использовать ~ в cron (раскрывается только в интерактивных сессиях)
- Забыли добавить
-hold
в xterm, и окно сразу закрывается
Если после всех настроек окно всё равно не появляется, проверьте:
- Права на .Xauthority (должны совпадать с пользователем cron-задачи)
- Запущен ли X-сервер (команда
ps aux | grep Xorg
) - Не блокирует ли брандмаузер соединение с локальным дисплеем
Как временное решение можно разрешить всем пользователям доступ к X-серверу (но это небезопасно!):
xhost +local:
Помните: DISPLAY=:0 – не всегда панацея. В системах с несколькими активными сессиями или при перезапуске X-сервера значение может измениться. Для критически важных задач лучше использовать методы с динамическим определением дисплея или переход на systemd-сервисы, которые интегрированы с пользовательской сессией.