I have a simple periodic cron task that must run as root. I want to use Zenity (or similar) to display a GUI informational dialog to user 1000 (or logged in user or all users) when the cron task finishes.
I’m looking for a simple, easy, quick solution. I’ll adapt to the requirements of such a simple solution.
Here’s where I am so far. My bash script works fine if run manually, but when Anacron runs it, nothing happens and I see Gtk-WARNING **: cannot open display
in the logs. I hoped it would display my dialog to the user after being run by cron.
I realize (after reading related questions) that cron needs to be decoupled from the GUI. If user 1000 is not logged in, I could take one of several options:
- do nothing (possibly acceptable because I want to keep it simple)
- display the dialog with completion message to the user when they log in next time (best)
- display some other type of notification (NOTE: the computer is a desktop system without a mail server installed)
I found these related questions:
x11 – Anacron job complains “Gtk-WARNING **: cannot open display” – Unix & Linux Stack Exchange
Anacron job complains “Gtk-WARNING **: cannot open display”
shell – How to pass data outside process for zenity progress? – Unix & Linux Stack Exchange
How to pass data outside process for zenity progress?
Example Code (from other question which is essentially the same as mine):
#!/bin/bash # Backs up the local filesystem on the external HDD sleep 60 DISPLAY=:0.0 zenity --question --text "Do you want to backup? Be sure to turn on the HDD." if [ $? -ne 0 ] then exit 1 fi *Do backup stuff here*
Error:
(zenity:9917): Gtk-WARNING **: cannot open display: run-parts: /etc/cron.daily/backup-on-external exited with return code 1
(I’m running Kubuntu, so a KDE solution would be even better than Zenity, but I already installed Zenity, so I can keep using it.)
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
Try adding something like the following to your ~/.xinitrc
(or ~/.xsession
if you use a login manager):
while true; do if [[ -a ~/.messages ]]; then zenity --info --text="$(printf "%q" $(cat ~/.messages))" rm ~/.messages fi sleep 10 done &
I haven’t tested this with zenity as I don’t have it and I’m assuming that .xsession
works as expected – I’ve never used a login manager.
The while
/done
block will execute indefinitely with a ten second delay between checks (the sleep 10
part). Each time there’s a check, the if
guard succeeds if there’s a non-empty file called .messages
in the user’s homedir. On success, the contents of the file are read into zenity and the file is removed.
I’m not thrilled with the printf
vomit, but it should be fine.
The content that gets put into ~/.messages
should be redirected from cron and you’ll need to make sure you change the owner and group of the file appropriately. Perhaps something like:
10 * * * * /usr/bin/mything && echo "mything completed" > /home/username/.messages && chown username:groupname /home/username/.messages
Method 2
My system is ubuntu 13.04. I ran a script similar to your’s via anacrontab and it works. Try this ..
Set up your crontab ..
$ cat /path/crontabfile SHELL=/bin/bash PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin * * * * * /bin/bash /path/anacron-tst/s1.sh
ALTERNATIVE: Set up your anacrontab ..
$ cat /etc/anacrontab ### original .. ,, .. SHELL=/bin/sh PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin HOME=/root LOGNAME=root # These replace cron's entries 1 5 cron.daily run-parts --report /etc/cron.daily 7 10 cron.weekly run-parts --report /etc/cron.weekly @monthly 15 cron.monthly run-parts --report /etc/cron.monthly ### end-original ### my custom lines .. SHELL=/bin/bash HOME=/home/me LOGNAME=me 1 2 me1 /bin/bash /path/anacron-tst/s1.sh
In your script ..
$ cat /path/anacron-tst/s1.sh PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin export DISPLAY=:0.0 export XAUTHORITY=/home/me/.Xauthority zenity --question --text "Backup time .. is HDD connected?" if [ $? -ne 0 ]; then echo "No confirmation .. quiting" exit 1 else echo "Will attempt backup now .." fi
This from man 5 anacrontab ..
.. lines can be of three kinds: job-description lines, environment assignments, or empty lines. Environment assignment lines are of the form: VAR = VALUE .. ,, .. The assignment takes effect from the next line to the end of the file, or to the next assignment of the same variable.
This is working with a the crontab installed for root. Please note that I have edited the script to include the line “export XAUTHORITY=/home/me/.Xauthority”. It needs that to work.
Method 3
Here’s a report on everything I found so far:
This solution from Ask Ubuntu
This is currently working for me and I haven’t seen any problems so far:
ACTIVE=$(ck-list-sessions | awk -F' = ' ' function f(){if(A=="TRUE"){P=U"t"D;gsub("'"'"'","",P);print P}} $1=="tunix-user"{U=$2} $1=="tx11-display"{D=$2} $1=="tactive"{A=$2} END{f()} /^[^t]/{f()} ') USERID=${ACTIVE% *} # tab USERNAME=$(getent passwd $USERID|cut -f1 -d':') DISPLAY=${ACTIVE#* } # tab DISPLAY="$DISPLAY" su $USERNAME -c "zenity --info --title='My Title' --text='My text. Notice the single quotes.'"
But I have been testing the notify-send command (mentioned here) and it would seem to be even more appropriate for my situation….
Unfortunately, it has the disadvantage in KDE that the notifications hide shortly and I haven’t found way to disable that timeout (-t 0 didn’t work). For my present use-case I tend to like a dialog box that has to be dismissed by a button click. Anyway, here are the details of notify-send:
notify-send command
The notify-send command allows you to send desktop notifications to the user via a notification daemon from the command line. This is useful to inform the desktop user about an event or display some form of information without getting in the user’s way. You need to install the following package:
$ sudo apt-get install libnotify-bin
In this example, send simple desktop notification from the command line, enter:
notify-send "rsnapshot done :)"
However, in the process of searching for solutions, I also found something that I absolutely love! I’ll be removing all calls to Zenity in all my scripts and replacing them with easybashgui.
easybashgui
http://sites.google.com/site/easybashgui/
EasyBashGUI is a Bash functions library for *BSD and GNU/Linux that
aims to give simple GUI functions using yad, gtkdialog, kdialog,
zenity, Xdialog, (c)dialog, whiptail or bash builtins depending on
KDE or GNOME running or not, Yad/Gtkdialog/Xdialog installed or not
and, eventually, X server running or not.
I also found Yad which will replace Zenity for me in the future. easybashgui can use/call Zenity, yad, gtkdialog, kdialog, Xdialog, (c)dialog, whiptail or bash builtins. So I’ll be phasing out Zenity and using yad where appropriate.
yad
Display graphical dialogs from shell scripts or command line – Google Project Hosting
http://code.google.com/p/yad/
Yad (yet another dialog) is a fork of Zenity with many improvements, such as custom buttons, additional dialogs, pop-up menu in notification icon and more.
There were two main reasons to make this fork. The first one is to
remove dependencies on deprecated libraries, such as libglade and
gnome-canvas. And the second one – as for me, Zenity looks like an
abandoned project. Its ChangeLog consists of just “bump version to…”
and “translation updated” for the long time, but many interesting
ideas which are ignored by developers/maintainers were in GNOME
Bugzilla.
a note
As don_crissti mentions, the solutions at this unix.stackexchange.com are probably relevant:
Open a window on a remote X display (why “Cannot open display”)?
Method 4
Based on Mel Boyce’s answer, here’s what worked for me. This is KDE-based. But I also tested it with Zenity and the same approach works. It is basically the same thing Mel Boyce recommended, but with a few tweaks to get it to work for me. I don’t delete the updateNotification.txt file, for example. And I don’t use printf.
The updater script includes this:
DATE_STAMP=` date` echo "t***The software has been updated to version ${LATEST} on ${DATE_STAMP}***" echo "The software has been updated to version ${LATEST} on ${DATE_STAMP}. Please close and reopen the program if it is current running. If you have any issues or questions, please write us at <a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f0838580809f8284b09588919d809c95de939f9dde">[email protected]</a> Thank you." > /home/$USERN/.updateNotification.txt
Then we have a script running in /home/$USERN/.kde/Autostart/updateNotificationChecker.sh
#!/bin/bash while true; do if [[ -s ~/.updateNotification.txt ]]; then read MSGFE < ~/.updateNotification.txt kdialog --title 'The software has been updated' --msgbox "$MSGFE" cat /dev/null > ~/.updateNotification.txt fi sleep 300 done exit 0
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0