我有一个简单的定期 cron 任务,必须以 root 身份运行。我想使用 Zenity(或类似的)在 cron 任务完成时向用户 1000(或登录用户或所有用户)显示 GUI 信息对话框。
我正在寻找一个简单、容易、快速的解决方案。我将适应这种简单解决方案的要求。
到目前为止,这就是我所在的位置。如果手动运行,我的 bash 脚本工作正常,但是当 Anacron 运行它时,什么也没有发生,我Gtk-WARNING **: cannot open display
在日志中看到。我希望它在 cron 运行后向用户显示我的对话框。
我意识到(在阅读相关问题后)cron 需要与 GUI 分离。如果用户 1000 未登录,我可以采取以下几种选择之一:
- 什么也不做(可能可以接受,因为我想保持简单)
- 当用户下次登录时向用户显示带有完成消息的对话框(最佳)
- 显示一些其他类型的通知(注意:计算机是没有安装邮件服务器的桌面系统)
我发现了这些相关问题:x11 - Anacron job抱怨“Gtk-WARNING **:无法打开显示” - 智库101 - 一个基于CC版权的问答分享平台 Anacron 作业抱怨“Gtk-WARNING **:无法打开显示”
shell - 如何将数据传递到进程外部以实现 zenity 进度? - Unix & Linux stacks 如何将数据传递到进程外部以获得 zenity 进度?
示例代码(来自其他问题,与我的问题基本相同):
#!/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*
错误:
(zenity:9917): Gtk-WARNING **: cannot open display:
run-parts: /etc/cron.daily/backup-on-external exited with return code 1
(我正在运行 Kubuntu,所以 KDE 解决方案甚至比 Zenity 更好,但我已经安装了 Zenity,所以我可以继续使用它。)
答案1
尝试将如下内容添加到您的~/.xinitrc
(或者~/.xsession
如果您使用登录管理器):
while true; do
if [[ -a ~/.messages ]]; then
zenity --info --text="$(printf "%q" $(cat ~/.messages))"
rm ~/.messages
fi
sleep 10
done &
我还没有用 zenity 测试过这个,因为我没有它,并且我假设它.xsession
按预期工作 - 我从未使用过登录管理器。
while
/块done
将无限期地执行,检查之间有十秒的延迟(sleep 10
部分)。每次检查时,如果在用户的主目录中if
调用了非空文件,则防护会成功。.messages
成功后,文件的内容将被读入 zenity 并被删除。
我对呕吐物并不感到兴奋printf
,但应该没问题。
放入的内容~/.messages
应该从 cron 重定向,并且您需要确保适当地更改文件的所有者和组。也许是这样的:
10 * * * * /usr/bin/mything && echo "mything completed" > /home/username/.messages && chown username:groupname /home/username/.messages
答案2
我的系统是ubuntu 13.04。我通过 anacrontab 运行了一个与您类似的脚本,并且它有效。尝试这个 ..
设置你的 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
替代方案:设置你的 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
在你的脚本中..
$ 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
这来自 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.
这是与为 root 安装的 crontab 一起使用的。请注意,我已经编辑了脚本以包含以下行“导出XAUTHORITY=/home/me/.Xauthority”。它需要这样才能发挥作用。
答案3
这是我迄今为止发现的所有内容的报告:
这个解决方案来自 Ask Ubuntu
这目前对我有用,到目前为止我还没有看到任何问题:
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.'"
但我一直在测试notify-send命令(提到这里)而且它似乎更适合我的情况......
不幸的是,它在 KDE 中的缺点是通知会很快隐藏,而且我还没有找到禁用该超时的方法(-t 0 不起作用)。对于我目前的用例,我倾向于喜欢一个必须通过单击按钮来关闭的对话框。无论如何,这里是通知发送的详细信息:
通知发送命令
通知发送命令允许您通过通知守护程序从命令行向用户发送桌面通知。这对于向桌面用户通知事件或显示某种形式的信息而不妨碍用户非常有用。您需要安装以下软件包:
$ sudo apt-get install libnotify-bin
在此示例中,从命令行发送简单的桌面通知,输入:
notify-send "rsnapshot done :)"
然而,在寻找解决方案的过程中,我也发现了一些我绝对喜欢的东西!我将删除所有脚本中对 Zenity 的所有调用,并用 easybashgui 替换它们。
EasybashGUI
http://sites.google.com/site/easybashgui/
EasyBashGUI 是一个用于 *BSD 和 GNU/Linux 的 Bash 函数库,旨在使用 yad、gtkdialog、kdialog、zenity、Xdialog、(c)dialog、whiptail 或 bash 内置函数提供简单的 GUI 函数,具体取决于 KDE 或 GNOME 是否运行,Yad /Gtkdialog/Xdialog 是否安装以及最终 X 服务器是否运行。
我还找到了 Yad,它将在未来取代 Zenity。 easybashgui 可以使用/调用 Zenity、yad、gtkdialog、kdialog、Xdialog、(c)dialog、whiptail 或 bash 内置函数。因此,我将逐步淘汰 Zenity,并在适当的情况下使用 yad。
亚德
从 shell 脚本或命令行显示图形对话框 - Google Project Hosting http://code.google.com/p/yad/
Yad(另一个对话框)是 Zenity 的一个分支,具有许多改进,例如自定义按钮、附加对话框、通知图标中的弹出菜单等等。
制作这个叉子有两个主要原因。第一个是删除对已弃用库的依赖,例如 libglade 和 gnome-canvas。第二个 - 对我来说,Zenity 看起来像是一个废弃的项目。长期以来,它的 ChangeLog 只包含“版本升级到...”和“翻译更新”,但许多被开发人员/维护人员忽略的有趣想法都在 GNOME Bugzilla 中。
一张纸条
正如 don_crissti 提到的,unix.stackexchange.com 上的解决方案可能是相关的:
答案4
根据梅尔·博伊斯的回答,这对我有用。这是基于 KDE 的。但我也用 Zenity 进行了测试,同样的方法也有效。这与梅尔·博伊斯推荐的基本相同,但进行了一些调整以使其适合我。例如,我不会删除 updateNotification.txt 文件。而且我不使用 printf 。
更新程序脚本包括:
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
然后我们在 /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