通知发送在crontab中不起作用


44

我编写了一个脚本,当我正在读一本漫画的新章节时,该脚本应该通知我。我使用命令notify-send来做到这一点。当我尝试在终端中运行该程序时,该程序有效。通知正在显示。但是,当我将其放置在crontab中时,不会显示通知。我非常确定该程序正在运行,因为我已经为我创建了一个文件。文件已创建,但未显示通知。

这是我的剧本

#!/bin/bash   
#One Piece Manga reminder    
#I created a file named .newop that contains the latest chapter.    
let new=$(cat ~/.newop)    
wget --read-timeout=30 -t20 -O .opreminder.txt http://www.mangareader.net/103/one-piece.html

if (( $(cat .opreminder.txt | grep "One Piece $new" | wc -l) >=1 ))    
then    
    (( new+=1 ))    
    echo $new    
    echo $new > ~/.newop    
    notify-send "A new chapter of One Piece was released."    
else    
    notify-send "No new chapter for One Piece."    
    notify-send "The latest chapter is still $new."    
fi        
exit

这就是我在crontab中写的

0,15,30,45 12-23 * * 3   /home/jchester/bin/opreminder.sh

提醒一下,crontab中的所有命令都必须以root身份运行,并且路径必须位于它们前面。在crontab中附加脚本和行会有所帮助,否则我们只是在猜测您的问题
Meer Borg

是的,对不起。我已经做了。
user158335 2013年

这是一个坏主意。通知是“ GUI”事物,cron是“控制台”事物。没有gaurentee,lib-notify将能够找到一种显示消息的方法。相反,您应该考虑将数据发送到stdout,并让cron的消息传递负责发送信息。通常会发送一封电子邮件。
coteyr

2
在某些情况下,设置DISPLAY变量也可能会有所帮助,例如:export DISPLAY=:0
谷氨酰胺

1
因为16.04,这个为我工作 */1 * * * * eval "export $(egrep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pgrep -u $LOGNAME gnome-session)/environ)";/usr/bin/notify-send -i appointment -c "im" "Keep Working"
KrIsHnA

Answers:


18

命令需要引用其位置。所以notify-send需要/usr/bin/notify-send

所有命令都必须具有其完整路径。

使用whereis notify-send命令查看您的命令在何处“存活”


2
那包括cat,wget,if,let,grep,echo等吗?
2013年

7
至少在我的系统notify-send上,PATH对于cron工作来说是偶数。请参阅下面的答案
krlmlr

2
它不是Ubuntu 17.04的解决方案。请参阅askubuntu.com/a/472769/413683askubuntu.com/a/834479/413683
Mateusz Piotrowski

2
这不是问题。问题在于cron脚本不在用户会话下运行,并且不了解用户登录会话的环境。由于notify-send需要连接到dbus会话总线以发送通知,因此,当二进制文件未连接到正确的会话总线时,从何处调用二进制文件就无关紧要。
dobey

2
这不是答案。当然,如果找不到可执行文件,它将无法运行,但是:1. 1. notify-send位于PATH上,因此它将被定位2.即使它不在PATH上,并且您指定完整路径,它仍然会不起作用,因为实际上必须为通知发送设置DBUS_SESSION_BUS_ADDRESS。正确的答案来自kmir。
克里斯·杰斯

31

至少在Gnome Shell中,13.04似乎有所不同。

首先,这是env从用户zzyxy(而非root)的cron作业运行时显示的内容:

HOME=/home/zzyxy
LOGNAME=zzyxy
PATH=/usr/bin:/bin
XDG_RUNTIME_DIR=/run/user/zzyxy
LANG=en_US.UTF-8
SHELL=/bin/sh
PWD=/home/zzyxy

要开始notify-send工作,DBUS_SESSION_BUS_ADDRESS按照DahitiF在ubuntuforums.org上的评论,似乎有必要设置环境变量。只需在您的实际职位描述之前添加以下内容:

eval "export $(egrep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pgrep -u $LOGNAME gnome-session)/environ)";

似乎没有必要设置DISPLAY


4
谢谢,这终于对我有用。在Xubuntu上,您必须更改gnome-sessionxfce4-session
shrx 2015年

这是适用于14.04的唯一答案,以及明显的暗示。
Wtower

1
我没有gnome-session使用它,gnome-shell而是使用它(注意还有一个,gnome-shell-calendar-server所以pgrep会得到2 pids)。我还需要,DISPLAY=:0因为我正在使用2个物理屏幕,但尚未定义。谢谢!
soyuka 2015年

如果您使用的Openbox(像CB ++)掉在openboxgnome-session
ACK_stoverflow '16

这是正确的答案,被接受的答案甚至都不正确,它谈论甚至不需要的DISPLAY变量,也无法解决问题。
Kris Jace

24

notify-send由cron启动时,命令不会在屏幕上显示该消息。只需在脚本顶部添加目标显示,例如:

export DISPLAY=:0

这也是我在14.10中必须做的。否则我会得到这个错误gdk_mir_display_open Failed to connect to Mir: Failed to connect to server socket: No such file or directory Option parsing failed: Cannot open display:
Joelmob 2014年

1
这个。并echo $DISPLAY在终端中使用以确保您的显示器确实是:0(通常是,但并非总是)。
2016年

只有这对我
有用

5

至少对于Ubuntu 14.04,以上的klrmr响应是正确的答案。似乎没有必要设置DISPLAY或明确表示通知发送的完整路径或其他通常在$ PATH中的内容。

下面是一个cron脚本,当笔记本电脑的电池电量过低时,我将使用它关闭虚拟机。上面的klrmr响应中的行设置DBUS_SESSION_BUS_ADDRESS是最终使警告正常运行的修改。

#!/bin/bash

# if virtual machine is running, monitor power consumption
if pgrep -x vmware-vmx; then
  bat_path="/sys/class/power_supply/BAT0/"
  if [ -e "$bat_path" ]; then
    bat_status=$(cat $bat_path/status)
    if [ "$bat_status" == "Discharging" ]; then
      bat_current=$(cat $bat_path/capacity)
      # halt vm if critical; notify if low
      if [ "$bat_current" -lt 10 ]; then
        /path/to/vm/shutdown/script
        echo "$( date +%Y.%m.%d_%T )" >> "/home/user/Desktop/VM Halt Low Battery"
        elif [ "$bat_current" -lt 15 ]; then
            eval "export $(egrep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pgrep -u $LOGNAME gnome-session)/environ)";
            notify-send -i "/usr/share/icons/ubuntu-mono-light/status/24/battery-caution.svg"  "Virtual machine will halt when battery falls below 10% charge."
      fi
    fi
  fi
fi

exit 0

这是完全为我工作,以及解决方案,我只是说了“EVAL ......”行到我的剧本,我从运行crontab -现在它完美的作品
物料间接开发

2

在我使用ubuntu 16.04的情况下,需要任何显式路径,我只需添加即可解决问题

显示=:0

在crontab的第一行,在调用notify-send之前。


这是使其在16.04上运行的唯一必要条件。
乔纳森·兰德伦

1

第一个罪魁祸首是您的crontab文件,还需要提及执行脚本所使用的用户名,最好将其保留为root用户。

0,15,30,45 12-23 * * 3 root   /home/jchester/bin/opreminder.sh

然后,您应该在脚本中使用GUI用户的user_name并在其前面加上“ sudo或su”来通知发送,以拥有GUI的用户身份执行命令

例如:

su gnome_user_name -c 'notify-send "summary" "body"'

要么

sudo -u gnome_user_name notify-send "summary" "body"

gnome_user_name启动GUI会话的用户名在哪里,是您登录的用户名;如果要使其成为动态选择,可以从以下位置获取它:

GNOME_USER=`ps -eo uname,cmd | grep gnome-session| head -1 | cut -d' ' -f1 `

例如:

su $GNOME_USER -c 'notify-send "summary" "body"'

要么

sudo -u $GNOME_USER notify-send "summary" "body"

1
我认为您的用户名长于X个字符时,您的用户名将被截断:例如,我的用户名是oniltonmaciel,但$GNOME_USER会显示onilton+(不起作用)
Onilton Maciel 2015年

用更好的命令修复了它
S471 2015年

1

二进制文件检索dbus地址的方式最近似乎已经改变。在具有“ notify-send 0.7.6”的Ubuntu 15.04(Vivid Vervet)上,需要以下两个变量:

export HOME=/home/$notify_user
export DISPLAY=:0.0

“ krlmlr”的语句可以很好地评估并设置正确的地址,但是该对话框不会从cron作业中弹出。


0

如果crontab中的脚本以root用户身份运行,则以上答案可能无法正常工作。试试这个功能,在16.04下对我来说效果很好:

notify_all() {
    local title=$1
    local msg=$2

    who | awk '{print $1, $NF}' | tr -d "()" |
    while read u d; do
        id=$(id -u $u)
        . /run/user/$id/dbus-session
        export DBUS_SESSION_BUS_ADDRESS
        export DISPLAY=$d
        su $u -c "/usr/bin/notify-send '$title' '$msg'"
    done 
}

(来源:https : //unix.stackexchange.com/a/344377/7286


0

最好依靠dbus-session流程,它应该在DBUS_SESSION_BUS_ADDRESS存在的所有系统上运行。

创建一个脚本:

#!/bin/bash
# notify.sh

environs=`pidof dbus-daemon | tr ' ' '\n' | awk '{printf "/proc/%s/environ ", $1}'`
export DBUS_SESSION_BUS_ADDRESS=`cat $environs 2>/dev/null | tr '\0' '\n' | grep DBUS_SESSION_BUS_ADDRESS | cut -d '=' -f2-`
export DISPLAY=:0

notify-send "It works!"

使它可执行:

$ chmod +x ~/notify.sh

将其添加到crontab中:

* * * * * $HOME/notify.sh

0

在ubuntu 15.10上花了所有的时间,不得不添加一个源来使用户正常使用env var。由于某种原因,我的显示也是:1。使用gnome-session首先结果pid进行DBUS_SESSION_BUS_ADDRESS查找。

# Crontab is
* 21 * * * /bin/sh /home/tristik/cron.sh
#!/bin/sh 
# cron.sh
# Notifies the user of date and time
source /home/tristik/.bashrc
pid=$(pgrep -u tristik gnome-session | head -n 1)
dbus=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$pid/environ | sed 's/DBUS_SESSION_BUS_ADDRESS=//' )
export DBUS_SESSION_BUS_ADDRESS=$dbus
export HOME=/home/tristik
export DISPLAY=:1
/usr/bin/notify-send 'title' "$(/bin/date)"

0

我已经使用以下配方将它与Ubuntu 15.10上的肉桂桌面配合使用:

if [ ! -v DBUS_SESSION_BUS_ADDRESS ]; then
  pid=$(pgrep -u $LOGNAME cinnamon-sessio)
  eval "export $(\grep -z DBUS_SESSION_BUS_ADDRESS /proc/$pid/environ)"
fi
notify-send "$RESUME" "$INFO"

诀窍是要意识到pgrep无法找到'cinnamon-session':

$ pgrep -u $LOGNAME cinnamon-session
$ pgrep -u $LOGNAME cinnamon
30789
30917
30965
30981
31039
31335
$ ps -a | \grep cinnamon
30789 tty2     00:00:00 cinnamon-sessio
30917 tty2     00:00:02 cinnamon-settin
30965 tty2     00:00:00 cinnamon-launch
30981 tty2     00:04:15 cinnamon
31039 tty2     00:00:00 cinnamon-killer
31335 tty2     00:00:00 cinnamon-screen
$ ps a | \grep cinnamon
 4263 pts/1    S+     0:00 grep cinnamon
30779 tty2     Ssl+   0:00 /usr/lib/gdm/gdm-x-session --run-script cinnamon-session-cinnamon
30789 tty2     Sl+    0:00 cinnamon-session --session cinnamon
30917 tty2     Sl+    0:02 /usr/lib/x86_64-linux-gnu/cinnamon-settings-daemon/cinnamon-settings-daemon
30965 tty2     Sl+    0:00 /usr/bin/python2 /usr/bin/cinnamon-launcher
30970 tty2     Sl+    0:00 /usr/lib/x86_64-linux-gnu/cinnamon-settings-daemon/csd-printer
30981 tty2     Sl+    4:16 cinnamon --replace
31039 tty2     Sl+    0:00 /usr/bin/python2 /usr/bin/cinnamon-killer-daemon
31335 tty2     Sl+    0:00 cinnamon-screensaver
$ pgrep -u $LOGNAME cinnamon-sessio
30789

我还必须使用\ grep,因为我的grep被别名为

$ alias grep
alias grep='grep -n --color=always'

0

我在Ubuntu 18.04上使用i3。我解决这个问题的方法是:

* * * * * XDG_RUNTIME_DIR=/run/user/$(id -u) notify-send Hey "this is dog!"


0

通过python3使用UTF-8区域设置在crontab中调用引起的问题。

TL; DR: crontab中带语言环境的前缀调用,如下所示:

*/5 * * * * LC_ALL=en_US.utf-8 LANG=en_US.utf-8 ~/.local/bin/watson-notify

另请参见click和python3

Traceback (most recent call last):
  File "/usr/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/usr/lib/python3/dist-packages/watson/__main__.py", line 6, in <module>
    cli.cli()
  File "/usr/lib/python3/dist-packages/click/core.py", line 759, in __call__
    return self.main(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/click/core.py", line 693, in main
    _verify_python3_env()
  File "/usr/lib/python3/dist-packages/click/_unicodefun.py", line 123, in _verify_python3_env
    'for mitigation steps.' + extra)
RuntimeError: Click will abort further execution because Python 3 was configured to use ASCII as encoding for the environment.  Consult http://click.pocoo.org/python3/ for mitigation steps.

This system supports the C.UTF-8 locale which is recommended.
You might be able to resolve your issue by exporting the
following environment variables:

    export LC_ALL=C.UTF-8
    export LANG=C.UTF-8

0

对于所有使用libnotify的crontab脚本,我使用以下命令:

notify_user() {
    local user=$(whoami)
    notify-send -u normal -t 4000 "System Backup" "Starting backup"
}

notify_user # and do other stuff

即使我在root模式下使用cron也可以。


0

您只需要X_user和X_userid。替换下面的命令。

Systemd解决方案

/etc/systemd/system/opreminder.service#服务文件

[Unit]
Descrption=some service to run

[Service]
User=[X_user]
ExecStart=/home/jchester/bin/opreminder.sh


/etc/systemd/system/opreminder.timer#定时器文件

[Unit]
Description=Some desc


[Timer]
OnCalendar=0,15,30,45 12-23 * * 3 

[Install]
WantedBy=list.timer.target

/home/jchester/bin/opreminder.sh#脚本

#!/usr/bin/env bash

sudo -u [X_user] DISPLAY=:0 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/[X_userid]/bus notify-send 'Hello world!' 'This is an example notification.'

如果已经使用目标用户设置了服务文件,则无需使用sudo -u

资料来源:https : //wiki.archlinux.org/index.php/Desktop_notifications#Usage_in_programming

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.