cron 在终端运行程序或运行图形应用
- 需求:利用 cron,定时在终端运行程序,以查看程序输出;或运行图形应用,如 gedit, xclock
cron 运行于非交互 shell,没有附属的终端,也独立于图形桌面。那么有没有办法实现上述需求呢?
我首先想到的是 gnome-terminal.
gnome-terminal -x do-job-command
可以实现在打开的终端中执行 do-job-command.
所以我尝试 cron 能不能打开 gnome-terminal,
cron 不是运行于 X.org server 下,因此它不知道必要的环境变量以打开 X.org server 应用,这些环境变量必须被定义。这里我们定义 DISPLAY.
加入计划任务 crontab -e
* * * * * export DISPLAY=:0 && /usr/bin/gnome-termimal
or
* * * * * env DISPLAY=:0 /usr/bin/gnome-termimal
无法打开(参考资料里说可以,可能跟系统有关),mate-terminal, x-terminal-emulator 也打不开,最终确认 xterm 可以。
实现方式 1
所以,计划任务可以是
0 4 * * * env DISPLAY=:0 /usr/bin/xterm -e do-job-command
实现方式 2
上述 gnome-terminal 在 cron 打不开,查看 cron 发送的邮件,出错信息如下:
Error constructing proxy for org.gnome.Terminal:/org/gnome/Terminal/Factory0:
+Could not connect: Connection refused
解决办法是:
dbus-launch gnome-terminal
dbus-launch 启动一个 Desktop Bus broker,供 gnome-terminal 和 gnome-terminal-server 通信。
最终,计划任务为
0 4 * * * export DISPLAY=:0 && /usr/bin/dbus-launch /usr/bin/gnome-terminal -x do-job-command
需要强调,dbus-launch 每次都会开启一个 dbus-daemon 进程,即使计划任务退出,该进程继续存在。如果计划任务频繁开启,就会产生很多 dbus-daemon 进程。所以,应当在计划任务退出时 kill 相应的 dbus-daemon 进程。注意,系统登录后也有自己的 dbus-daemon 进程,不要 kill 错了。
实现方式 3 (2 的改进)
方式 2 开启一个新的 Desktop Bus broker ,有上述一些缺陷。可以利用系统登录后现有的 Desktop Bus broker.
$ echo $DBUS_SESSION_BUS_ADDRESS
unix:abstract=/tmp/dbus-FzlL8v7efh
计划任务为
* * * * * env DISPLAY=:0 env DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-FzlL8v7efh /usr/bin/gnome-terminal -x do-job-command
实现方式 4
* * * * * DISPLAY=:0 /usr/bin/exo-open --launch TerminalEmulator do-job-command
出错:Failed to execute default Terminal Emulator. Input/output error.
TerminalEmulator 即 x-terminal-emulator
$ sudo update-alternatives --config x-terminal-emulator
There are 6 choices for the alternative x-terminal-emulator (providing /usr/bin/x-terminal-emulator).
Selection Path Priority Status
------------------------------------------------------------
* 0 /usr/bin/gnome-terminal.wrapper 40 auto mode
1 /usr/bin/gnome-terminal.wrapper 40 manual mode
2 /usr/bin/koi8rxterm 20 manual mode
3 /usr/bin/lxterm 30 manual mode
4 /usr/bin/mate-terminal.wrapper 30 manual mode
5 /usr/bin/uxterm 20 manual mode
6 /usr/bin/xterm 20 manual mode
Press <enter> to keep the current choice[*], or type selection number:
可知,调用的是 gnome-terminal。所以,同方式 3,提供 DBUS_SESSION_BUS_ADDRESS 变量即可。
最终的计划任务为
* * * * * DISPLAY=:0 DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-MsQxIw6b3X /usr/bin/exo-open --launch TerminalEmulator do-job-command
实现方式 5
将程序输出重定向到已经打开的终端
用 tty
查看当前终端
运行级别 3 下是 /dev/tty1-6
运行级别 5 ,或者 ssh 登录,是 /dev/pts/*
计划任务为
* * * * * do-job-command > /dev/pts/17
关于终端与控制台,参考 https://www.cnblogs.com/vk83/archive/2013/06/01/3112700.html
参考资料
- https://askubuntu.com/questions/309853/getting-output-from-a-cron-job-on-the-terminal
- https://wiki.archlinux.org/index.php/Cron#Running_X.org_server-based_applications
- https://superuser.com/questions/351528/open-a-terminal-from-a-crontab
- https://unix.stackexchange.com/questions/325346/how-to-execute-the-command-in-cronjob-to-display-the-output-in-terminal
- https://askubuntu.com/questions/1020965/how-do-i-set-cron-to-send-emails