Powiadomienie-wysyłanie nie działa z crontab

44

Stworzyłem skrypt, który powinien powiadomić mnie, gdy czytam nowy rozdział mangi. W tym celu użyłem polecenia notify-send. Program działa, gdy próbuję uruchomić go w terminalu. Powiadomienie wyświetla się. Jednak gdy umieściłem to w moim crontabie, powiadomienie nie wyświetla się. Jestem pewien, że program działa, ponieważ stworzyłem dla niego plik. Plik został utworzony, ale powiadomienie nie zostało wyświetlone.

Oto mój skrypt

#!/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

A oto co napisałem w moim crontabie

0,15,30,45 12-23 * * 3   /home/jchester/bin/opreminder.sh
użytkownik158335
źródło
Przypominamy, że wszystkie polecenia w crontab muszą mieć przed sobą ścieżkę, gdy działają jako root. Dołączenie skryptu i wiersza w crontabie pomogłoby, w przeciwnym razie zgadujemy tylko twój problem
Meer Borg
Tak, przepraszam. Właśnie zrobiłem.
user158335
To zły pomysł. Powiadomienia to „GUI”, cron to „konsola”. Nie ma gwarancji, że lib-powiadomienie będzie w stanie znaleźć sposób na wyświetlenie wiadomości. Zamiast tego powinieneś rozważyć wysłanie danych na standardowe wyjście i pozwolić, aby wiadomości crona zajęły się wysyłaniem informacji. Zwykle wysyłany jest e-mail.
coteyr
2
W niektórych przypadkach pomocne może być również ustawienie zmiennej DISPLAY, np export DISPLAY=:0. : .
Glutanimate
1
Dla 16.04mnie ten zadziałał */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

Odpowiedzi:

18

Polecenia muszą odnosić się do ich lokalizacji. Tak notify-sendmusi być/usr/bin/notify-send

Wszystkie polecenia muszą mieć pełną ścieżkę.

Użyj whereis notify-sendpolecenia, aby zobaczyć, gdzie „żyją” Twoje polecenia

Meer Borg
źródło
2
Czy obejmuje to cat, wget, if, let, grep, echo itp.?
user158335
7
Przynajmniej w moim systemie notify-sendjest na PATHparze dla zadania cron. Zobacz moją odpowiedź poniżej.
krlmlr 17.09.13
2
To nie jest rozwiązanie dla Ubuntu 17.04. Zamiast tego zobacz askubuntu.com/a/472769/413683 i askubuntu.com/a/834479/413683 .
Mateusz Piotrowski
2
To nie jest problem. Problem polega na tym, że skrypty cron nie działają w sesji użytkownika i nie mają pojęcia o środowisku sesji logowania użytkownika. Ponieważ powiadomienie-wysyłanie wymaga połączenia z magistralą sesji dbus w celu wysłania powiadomienia, nie będzie miało znaczenia, z której ścieżki jest wywoływany plik binarny, gdy nie łączy się z właściwą magistralą sesji.
dobey,
2
To NIE jest odpowiedź. Jasne, jeśli nie można zlokalizować pliku wykonywalnego, nie uruchomi się, ALE: 1. powiadomienie-wysyłanie znajduje się na ŚCIEŻCE, więc będzie zlokalizowane 2. nawet jeśli nie było na ŚCIEŻCE, a Ty podasz pełną ścieżkę, którą nadal będzie nie działa, ponieważ tak naprawdę DBUS_SESSION_BUS_ADDRESS musi być ustawiony na powiadomienie-wysyłanie. Prawidłowa odpowiedź to kmir.
Kris Jace
31

W 13.04 wydaje się inaczej, przynajmniej w Gnome Shell.

Po pierwsze, to jest envdrukowane po uruchomieniu z zzyxyzadania cron użytkownika (nie roota):

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

Aby zabrać się notify-senddo pracy, wydaje się konieczne ustawienie DBUS_SESSION_BUS_ADDRESSzmiennej środowiskowej, zgodnie z komentarzem DahitiF na ubuntuforums.org. Po prostu wstaw następujące informacje do faktycznego opisu stanowiska:

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

Ustawienie nie wydaje się konieczne DISPLAY.

krlmlr
źródło
4
Dzięki, to w końcu dla mnie zadziałało. Na Xubuntu musisz zmienić gnome-sessionna xfce4-session.
shrx
To jedyna odpowiedź na pracę z 14.04, wraz z oczywistą nutą przyjętej.
Wtower
1
Nie miałem gnome-sessioni użyłem gnome-shellzamiast tego (uważaj, jest też gnome-shell-calendar-servertak, pgrepże dostaniesz 2 pids). Potrzebowałem również, DISPLAY=:0ponieważ używam 2 ekranów fizycznych i nie zostało to zdefiniowane. Dzięki!
soyuka
Jeśli używasz Openbox (jak w CB ++) zamień openboxna gnome-session.
ACK_stoverflow
TO jest poprawna odpowiedź, a zaakceptowana odpowiedź nie jest nawet poprawna, mówi o zmiennej DISPLAY, która nawet nie jest potrzebna, ani też nie rozwiązuje problemu.
Kris Jace
24

Polecenie notify-sendnie wyświetla komunikatu na ekranie po uruchomieniu przez crona. Wystarczy dodać wyświetlanie docelowe u góry skryptu, na przykład:

export DISPLAY=:0
Martin Höger
źródło
Tak też musiałem zrobić w 14.10. W przeciwnym razie 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:
dostałbym
1
To. I użyj echo $DISPLAYw terminalu, aby upewnić się, że Twój wyświetlacz naprawdę jest :0(zwykle jest, ale nie zawsze).
Mark
Tylko to działało dla mnie, używam Linux Mint
Harendra Singh
5

Przynajmniej dla Ubuntu 14.04 powyższa odpowiedź klrmr jest poprawną odpowiedzią. Nie wydaje się konieczne ustawianie WYŚWIETLACZA lub określanie pełnych ścieżek dla powiadomienia-wysyłania lub czegokolwiek innego zwykle w $ PATH.

Poniżej znajduje się skrypt crona, którego używam do zamykania maszyny wirtualnej, gdy stan baterii laptopa staje się zbyt niski. Ustawienie linii DBUS_SESSION_BUS_ADDRESS w powyższej odpowiedzi klrmr to modyfikacja, która w końcu sprawiła, że ​​ostrzeżenia działały poprawnie.

#!/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
nmax
źródło
To rozwiązanie również działało idealnie dla mnie, właśnie dodałem wiersz „eval ...” do mojego skryptu, który uruchamiam z crontab - teraz działa idealnie
Mtl Dev
2

W moim przypadku z Ubuntu 16.04 wymagana była jakakolwiek wyraźna ścieżka, rozwiązuję problem po prostu dodając

WYŚWIETLACZ =: 0

na pierwszych liniach crontab, przed połączeniem powiadom-wyślij.

Raul R.
źródło
Jest to jedyna rzecz niezbędna do uruchomienia go 16.04.
Jonathan Landrum
1

Pierwszym winowajcą jest twój plik crontab, musisz również wspomnieć o nazwie użytkownika, z którą skrypt ma zostać wykonany, lepiej zachowaj go jako root

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

a następnie powinieneś użyć nazwy użytkownika GUI w skrypcie i przygotować go do powiadomienia-send z „sudo lub su”, aby wykonać polecenie jako użytkownik będący właścicielem GUI

przykład:

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

lub

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

gdzie gnome_user_namejest nazwa użytkownika, który rozpoczął sesję GUI, to ty się zalogowałeś, a jeśli chcesz, aby była dynamiczna, możesz ją pobrać z

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

przykład:

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

lub

sudo -u $GNOME_USER notify-send "summary" "body"
S471
źródło
1
Myślę, że gdy twoja nazwa użytkownika jest dłuższa niż X znaków, twoja nazwa użytkownika jest obcięta: Na przykład moja nazwa użytkownika to oniltonmaciel, ale $GNOME_USERpokaże się onilton+(nie działa)
Onilton Maciel
naprawiono to z lepszym poleceniem
S471
1

Wygląda na to, że sposób, w jaki binarny pobiera adres dbus, ostatnio się zmienił. W systemie Ubuntu 15.04 (Vivid Vervet) z opcją „powiadom-wyślij 0.7.6” potrzebne są następujące dwie zmienne:

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

Instrukcja „krlmlr” ocenia dobrze i ustawia poprawny adres, ale okno dialogowe nie wyskoczy z zadania cron.

tanza
źródło
0

Jeśli twój skrypt w crontabie działa jako root, powyższe odpowiedzi prawdopodobnie nie będą działać. Wypróbuj tę funkcję, która działa dobrze dla mnie w 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 
}

(Źródło: https://unix.stackexchange.com/a/344377/7286 )

mivk
źródło
0

Lepiej polegać na dbus-sessionprocesie, powinien działać na wszystkich systemach, w których DBUS_SESSION_BUS_ADDRESSjest obecny.

Utwórz skrypt:

#!/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!"

Spraw, by był wykonywalny:

$ chmod +x ~/notify.sh

Dodaj to do crontab:

* * * * * $HOME/notify.sh
denis.peplin
źródło
0

To trwało wieczność, aby pracować nad Ubuntu 15.10. Musiałem dodać źródło, aby uzyskać normalne zmienne env użytkowników. mój wyświetlacz był również: 1 z jakiegoś powodu. Korzystanie z pierwszych wyników sesji gnome dla wyszukiwania 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
źródło
0

Właśnie dostałem to do pracy z cynamonowym pulpitem na Ubuntu 15.10, przy użyciu następującego przepisu:

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"

Sztuką było uświadomienie sobie, że „sesja cynamonowa” jest zbyt długa, aby pgrep mógł znaleźć:

$ 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

Musiałem także użyć \ grep, ponieważ mój grep jest aliasowany do

$ alias grep
alias grep='grep -n --color=always'
John Frankland
źródło
0

Używam i3 na Ubuntu 18.04. Mój sposób na rozwiązanie tego:

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

Pan Goferito
źródło
0

Problem spowodowany wywołaniem python3crontab z UTF-8ustawieniami narodowymi.

TL; DR: wywołanie prefiksu w crontab w / locale jak w:

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

Zobacz także kliknij i 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
źródło
0

Dla wszystkich skryptów crontab korzystających z libnotify używam tego:

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

notify_user # and do other stuff

Działa, nawet jeśli używam crona w trybie root.

azzamsa
źródło
0

Wszystko czego potrzebujesz to X_user i X_userid. Wymień oba w poni szym poleceniu.

Rozwiązanie z systemd

/etc/systemd/system/opreminder.service #Service file

[Unit]
Descrption=some service to run

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


/etc/systemd/system/opreminder.timer #timer

[Unit]
Description=Some desc


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

[Install]
WantedBy=list.timer.target

/home/jchester/bin/opreminder.sh # Skrypt

#!/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.'

Nie trzeba używać sudo -u, jeśli plik usługi jest już ustawiony dla docelowego użytkownika

Źródło: https://wiki.archlinux.org/index.php/Desktop_notifications#Usage_in_programming

Bruno
źródło