How to programmatically find the current value of DISPLAY when DISPLAY is unset? (for use in crontab)
I have a script that runs via cron to change the desktop wallpaper. I can get it to work by exporting the DISPLAY variable.
But the issue I am concerned about it that the script should work on all systems. How to find the value of DISPLAY set by the X server without using $DISPLAY?
So how can I find the correct value for DISPLAY
programmatically. I can get it to work only when DISPLAY=:1
. Setting it to ":0"
makes the script exit with
No protocol specified
Cannot open display.
You can't for sure. You have to make assumptions.
Pretend you're cron
and you're facing the worst case scenario for a second: there are multiple users logged in, and each user is running multiple X sessions. You'll have to guess the user (easy enough, we're executing their crontab) and one of that user's X sessions.
If we want to assume the user is running one and only one X session from a tty, and get that session's $DISPLAY
value we can use 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
For example here I'm logged in on tty1, on tty2 (where I'm running an X session) and on pts/3 (the terminal from which I'm running the command).
With a bit of parsing:
% w $(id -un) | awk 'NF > 7 && $2 ~ /tty[0-9]+/ {print $3; exit}'
:1
So, assuming all the above:
0 0 * * * DISPLAY=$(w $(id -un) | awk 'NF > 7 && $2 ~ /tty[0-9]+/ {print $3; exit}') command
Will make cron
execute command
with $DISPLAY
set to the first X session running in a tty's $DISPLAY
value found for the user.
For a more detailed discussion, refer to https://unix.stackexchange.com/questions/17255/is-there-a-command-to-list-all-open-displays-on-a-machine
I will simply list the relevant information from that answer here:
There seems to be two simple ways to find the X server instances running on your system.
-
w
:
Thew
command lists all the open displays. You can then useawk
to filter out the information you need. The values underFROM
are the values corresponding toDISPLAY
.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
-
Local displays correspond to a socket in
/tmp/.X11-unix
, so we can simply do:cd /tmp/.X11-unix && for x in X*; do echo ":${x#X}"; done