Уведомление-отправка не работает из 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
user158335
источник
Напоминаем, что все команды в crontab должны иметь свой путь перед ними, поскольку они запускаются от имени пользователя root. Присоединение скрипта и строки в crontab поможет, иначе мы просто угадаем вашу проблему
Меер Борг,
Да извини. Я только что сделал.
user158335
Это плохая идея. Уведомления - это «GUI», а cron - «консоль». Нет гарантии, что lib-notify сможет найти способ отображения сообщения. Вместо этого вам следует рассмотреть возможность отправки данных в stdout, и пусть служба сообщений cron позаботится об отправке информации. Обычно письмо отправляется.
Coteyr
2
В некоторых случаях , устанавливая переменную DISPLAY вверх может помочь , а также, например: export DISPLAY=:0.
Glutanimate
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

Ответы:

18

Команды должны ссылаться на их местоположение. Так notify-sendдолжно быть/usr/bin/notify-send

Все команды должны иметь свой полный путь.

Используйте whereis notify-sendкоманду, чтобы увидеть, где ваши команды "живут"

Меер Борг
источник
2
Включает ли это cat, wget, if, let, grep, echo и т. Д.?
user158335
7
По крайней мере , в моей системе, notify-sendнаходится на PATHдаже хрон. Смотрите мой ответ ниже.
13
2
Это не решение для Ubuntu 17.04. См. Askubuntu.com/a/472769/413683 и askubuntu.com/a/834479/413683 вместо этого.
Матеуш Пиотровски
2
Это не проблема. Проблема заключается в том, что сценарии cron не запускаются во время сеанса пользователя и не имеют представления о среде сеанса входа пользователя в систему. Поскольку notify-send требует подключения к сеансной шине dbus для отправки уведомления, не имеет значения, по какому пути вызывается двоичный файл, если он не подключается к правильной сеансовой шине.
Добе
2
Это НЕ ответ. Конечно, если исполняемый файл не может быть найден, он не запустится, НО: 1. notify-send находится в PATH, поэтому он будет расположен 2. даже если он не был в PATH, и вы указали полный путь, он все равно будет не работает, потому что на самом деле DBUS_SESSION_BUS_ADDRESS должен быть установлен для уведомления-отправки. И правильный ответ от Кмир.
Крис Джейс
31

Вещи, кажется, отличаются от 13.04, по крайней мере, в Gnome Shell.

Во-первых, это то, что 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.

krlmlr
источник
4
Спасибо, это то, что наконец-то сработало для меня. В Xubuntu вы должны перейти gnome-sessionна xfce4-session.
shrx
Это единственный ответ на работу за 14.04, наряду с очевидным намеком на принятый.
Wtower
1
Я не имел gnome-sessionи использовать gnome-shellвместо (будьте осторожны , есть и gnome-shell-calendar-serverтак pgrepбудет получить 2 ИДП). Я также нуждался, DISPLAY=:0потому что я использую 2 физических экрана, и это не было определено. Благодарность!
союка
Если вы используете Openbox (как в CB ++), поменяйте его openboxна gnome-session.
ACK_stoverflow
Это правильный ответ, и принятый ответ даже не правильный, он говорит о переменной DISPLAY, которая даже не нужна, и фактически не решает проблему.
Крис Джейс
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
1
Это. И используйте echo $DISPLAYв терминале, чтобы убедиться, что ваш дисплей действительно :0(как правило, но не всегда).
Отметить
Только это сработало для меня, я использую Linux Mint
Харендра Сингх
5

По крайней мере, для Ubuntu 14.04 ответ klrmr выше является правильным ответом. По-видимому, нет необходимости устанавливать DISPLAY или указывать полные пути для уведомления-отправки или чего-либо иного, как правило, в $ PATH.

Ниже приведен скрипт cron, который я использую для выключения виртуальной машины, когда состояние батареи ноутбука становится слишком низким. Установка строки DBUS_SESSION_BUS_ADDRESS в ответе klrmr выше - это модификация, которая, наконец, заставила предупреждения работать правильно.

#!/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 - теперь он работает отлично
Mtl Dev
2

В моем случае с Ubuntu 16.04 требовался любой явный путь, я решаю проблему, просто добавляя

DISPLAY =: 0

на первых линиях crontab, перед вызовом notify-send.

Рауль Р.
источник
Это единственное, что нужно, чтобы заставить его работать 16.04.
Джонатан Ландрум
1

Первым виновником является ваш файл crontab, вам также нужно указать имя пользователя, с которым должен выполняться скрипт, лучше сохранить его как root

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

а затем вы должны использовать user_name пользователя GUI внутри скрипта и добавить его к уведомлению-отправке с помощью "sudo или su", чтобы выполнить команду как пользователь, который владеет GUI

пример :

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

или

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

где gnome_user_nameимя пользователя, который запустил сеанс графического интерфейса пользователя, это вы вошли в систему, и если вы хотите сделать его динамическим выбором, вы можете получить его от

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"
S471
источник
1
Я думаю, что когда ваше имя пользователя длиннее X символов, ваша usernma усекается: например, мое имя пользователя oniltonmaciel, но $GNOME_USERбудет отображаться onilton+(не работает)
Onilton Maciel
исправил это с лучшей командой
S471
1

Способ, которым двоичный файл получает адрес dbus, в последнее время, похоже, изменился. В Ubuntu 15.04 (Vivid Vervet) с уведомлением-отправкой 0.7.6 необходимы следующие две переменные:

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

Утверждение 'krlmlr' оценивает отлично и устанавливает правильный адрес, но диалог не появляется из задания cron.

Tanza
источник
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 )

mivk
источник
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
denis.peplin
источник
0

Это заняло целую вечность, чтобы заставить работать на Ubuntu 15.10. Пришлось добавить источник, чтобы пользователи получали нормальные env vars. мой дисплей был: 1 по какой-то причине. Использование pid результатов первого сеанса gnome для поиска 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)"
Tristik
источник
0

Я только что получил это для работы с рабочим столом cinnamon в 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"

Хитрость заключалась в том, чтобы понять, что «cinnamon-session» слишком длинен для pgrep:

$ 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

Я использую i3 на Ubuntu 18.04. Мой способ решить это:

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

Мистер Гоферито
источник
0

Проблема вызвана вызовом python3в crontab с UTF-8локалью.

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
Gen.Stack
источник
0

Для всех скриптов crontab, которые используют libnotify, я использую это:

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

notify_user # and do other stuff

Это работает, даже если я использую cron в режиме root.

azzamsa
источник
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 #timer file

[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

Bruno
источник