3

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:

  1. do nothing (possibly acceptable because I want to keep it simple)
  2. display the dialog with completion message to the user when they log in next time (best)
  3. 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.)

6
  • This might be my solution: askubuntu.com/a/94036/36661 However, I'm wondering what the result will be if no user is logged in at the GUI.
    – MountainX
    Jun 21, 2013 at 21:31
  • 1
    Given your requirement for a notice if the user logs in later, why not just have any notices written somewhere like /home/user/.messages and then set up something to check that file every so often that's running under X and as the user?
    – Mel Boyce
    Jun 23, 2013 at 9:15
  • @MelBoyce - interesting idea, but that turns it into a recursive question ;-) How to display a GUI dialog to the user after a message is written to somewhere like /home/user/.messages
    – MountainX
    Jun 23, 2013 at 18:27
  • Run a process from .xinitrc that check the presence of that file every n seconds and if it exists, display the contents in something like zenity and delete the file?
    – Mel Boyce
    Jun 24, 2013 at 11:22
  • @MelBoyce - thanks but unfortunately, that doesn't give me enough info. How would I run a process from .xinitrc? What process? If you give me more info, I'll try it.
    – MountainX
    Jun 24, 2013 at 18:42

4 Answers 4

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
5
  • Thanks! I will test this today. It sounds like exactly what I need. I assume it will work and if it does, I'll accept your answer.
    – MountainX
    Jun 25, 2013 at 17:51
  • It's close, but your concerns about printf were valid. When I get a final version that works, I can post it here. But I think the concept is the right one. Thanks.
    – MountainX
    Jun 26, 2013 at 1:25
  • actually, I can't get it to work...
    – MountainX
    Jun 27, 2013 at 3:56
  • What's the issue?
    – Mel Boyce
    Jun 27, 2013 at 12:36
  • I added an answer with the solution that I finally got working. It is very close to what you suggested. Thanks!
    – MountainX
    Jun 27, 2013 at 17:12
1

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.

2
  • using anacrontab instead of crontab is a good suggestion. But in my case, the script also needs to be run as root.
    – MountainX
    Sep 23, 2013 at 0:49
  • 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. Sep 23, 2013 at 20:22
0

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")?

1
  • @don_crissti - Thanks. It sounds like you have a lot of experience in this area. Do you agree that notify-send is the best option or do you think one of the other options is better?
    – MountainX
    Jun 23, 2013 at 4:59
0

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 [email protected]. 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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .