Notify-send funktioniert nicht von crontab aus

44

Ich habe ein Skript erstellt, das mich benachrichtigen soll, wenn ich ein neues Kapitel über Manga lese. Ich habe dazu den Befehl notify-send verwendet. Das Programm funktioniert, wenn ich versuche, es im Terminal auszuführen. Die Benachrichtigung wird angezeigt. Wenn ich dies jedoch in meine Crontab legte, wird die Benachrichtigung nicht angezeigt. Ich bin mir ziemlich sicher, dass das Programm ausgeführt wird, seit ich eine Datei für mich erstellt habe. Die Datei wurde erstellt, aber die Benachrichtigung wurde nicht angezeigt.

Hier ist mein Drehbuch

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

Und hier ist, was ich in meinem crontab schrieb

0,15,30,45 12-23 * * 3   /home/jchester/bin/opreminder.sh
user158335
quelle
Nur zur Erinnerung, alle Befehle in crontab müssen ihren Pfad vor sich haben, wenn sie als root ausgeführt werden. Das Anhängen von Skript und Zeile in crontab würde helfen, sonst raten wir nur zu Ihrem Problem
Meer Borg
Ja entschuldigung. Ich habe es gerade getan.
user158335
Das ist eine schlechte Idee. Benachrichtigungen sind eine "GUI" Sache, Cron ist eine "Konsole" Sache. Es gibt keine Garantie, dass lib-notify eine Möglichkeit finden wird, die Nachricht anzuzeigen. Stattdessen sollten Sie in Betracht ziehen, Daten an stdout zu senden, und crons Nachrichtenübermittlung sich um das Senden der Informationen kümmern. Normalerweise wird eine E-Mail gesendet.
Coteyr
2
In einigen Fällen kann auch das Einstellen der DISPLAY-Variablen hilfreich sein, z export DISPLAY=:0.
Glutanimate
1
Denn 16.04dieser hat für mich */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"
funktioniert

Antworten:

18

Befehle müssen auf ihre Position verweisen. So notify-sendmuss es sein/usr/bin/notify-send

Alle Befehle müssen ihren vollständigen Pfad haben.

Verwenden Sie den whereis notify-sendBefehl, um zu sehen, wo Ihre Befehle "leben"

Meer Borg
quelle
2
Umfasst das cat, wget, if, let, grep, echo usw.?
user158335
7
Zumindest auf meinem System notify-sendist das PATHgerade für einen Cronjob. Siehe meine Antwort unten.
krlmlr
2
Es ist nicht die Lösung für Ubuntu 17.04. Siehe stattdessen askubuntu.com/a/472769/413683 und askubuntu.com/a/834479/413683 .
Mateusz Piotrowski
2
Das ist nicht das Problem. Das Problem ist, dass Cron-Skripte nicht unter der Benutzersitzung ausgeführt werden und keine Vorstellung von der Umgebung der Anmeldesitzung des Benutzers haben. Da zum Senden der Benachrichtigung die Verbindung zu einem dbus-Sitzungsbus erforderlich ist, spielt es keine Rolle, von welchem ​​Pfad die Binärdatei aufgerufen wird, wenn keine Verbindung zum richtigen Sitzungsbus hergestellt wird.
Dobey
2
Dies ist NICHT die Antwort. Sicher, wenn die ausführbare Datei nicht gefunden werden kann, wird sie nicht ausgeführt, ABER: 1. notify-send befindet sich auf dem PFAD, so dass sie sich befindet funktioniert nicht, da eigentlich DBUS_SESSION_BUS_ADDRESS für notify-send gesetzt sein muss. Und die richtige Antwort kommt von kmir.
Kris Jace
31

Am 13.04 sieht es anscheinend anders aus, zumindest in Gnome Shell.

Zunächst wird Folgendes envgedruckt, wenn zzyxyder Cron-Job des Benutzers (nicht des Roots) ausgeführt wird:

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

Um notify-sendan die Arbeit zu kommen, scheint es notwendig zu sein, die DBUS_SESSION_BUS_ADDRESSUmgebungsvariable gemäß DahitiFs Kommentar auf ubuntuforums.org zu setzen. Stellen Sie einfach Folgendes vor Ihre eigentliche Stellenbeschreibung:

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

Es scheint nicht notwendig zu sein, einzustellen DISPLAY.

krlmlr
quelle
4
Danke, das hat endlich bei mir geklappt. Auf Xubuntu, müssen Sie ändern gnome-sessionzu xfce4-session.
shrx
Dies ist die einzige Antwort für 14.04, zusammen mit dem offensichtlichen Hinweis auf die akzeptierte.
Wtower
1
Ich hatte keine gnome-sessionund benutzte gnome-shellstattdessen (sei vorsichtig, es gibt auch eine, gnome-shell-calendar-serverdamit pgrep2 Pids bekommen). Ich brauchte auch, DISPLAY=:0weil ich 2 Bildschirme verwende und es nicht definiert wurde. Vielen Dank!
Sojuka
Wenn Sie Openbox verwenden (wie bei CB ++), tauschen Sie openboxfür gnome-session.
ACK_stoverflow
Dies ist die richtige Antwort, und die akzeptierte Antwort ist nicht einmal richtig. Es handelt sich um eine DISPLAY-Variable, die nicht einmal benötigt wird und das Problem auch nicht wirklich löst.
Kris Jace
24

Der Befehl notify-sendzeigt die Meldung nicht auf Ihrem Bildschirm an, wenn er von cron gestartet wird. Fügen Sie einfach die Zielanzeige oben in Ihr Skript ein, zum Beispiel:

export DISPLAY=:0
Martin Höger
quelle
Das musste ich auch in 14.10 tun. Sonst würde ich diesen Fehler bekommengdk_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
Diese. Und verwenden Sie echo $DISPLAYin einem Terminal, um sicherzustellen, dass Ihr Display wirklich ist :0(normalerweise, aber nicht immer).
Mark
Nur das hat bei mir funktioniert, ich benutze Linux Mint
Harendra Singh
5

Zumindest für Ubuntu 14.04 ist die obige Antwort von klrmr die richtige Antwort. Es scheint nicht erforderlich zu sein, DISPLAY einzustellen oder vollständige Pfade für das Senden von Benachrichtigungen oder andere normalerweise in $ PATH enthaltene Elemente anzugeben.

Unten ist ein Cron-Skript, mit dem ich eine virtuelle Maschine herunterfahre, wenn der Akkustand eines Laptops zu niedrig wird. Die Zeileneinstellung DBUS_SESSION_BUS_ADDRESS in der obigen Antwort von klrmr ist die Änderung, durch die die Warnungen schließlich korrekt funktionieren.

#!/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
quelle
Dies war die Lösung, die auch für mich perfekt funktionierte. Ich habe meinem Skript die Zeile "eval ..." hinzugefügt, die ich von crontab aus laufe - jetzt funktioniert es perfekt
Mtl Dev
2

In meinem Fall mit Ubuntu 16.04 war ein expliziter Pfad erforderlich. Ich löse das Problem, indem ich ihn hinzufüge

ANZEIGE =: 0

in den ersten zeilen der crontab, vor anruf benachrichtigen-senden.

Raul R.
quelle
Dies ist das einzige, was nötig ist, um es am 16.04 zum Laufen zu bringen.
Jonathan Landrum
1

Der erste Schuldige ist Ihre crontab-Datei. Sie müssen auch den Benutzernamen angeben, mit dem das Skript ausgeführt werden soll. Behalten Sie es besser als root bei

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

und dann sollten Sie den Benutzernamen des GUI-Benutzers innerhalb des Skripts verwenden und ihn voranstellen, um mit "sudo oder su" zu benachrichtigen und zu senden, damit der Befehl als Benutzer ausgeführt wird, dem die GUI gehört

Beispiel:

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

oder

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

Wo gnome_user_nameist der Benutzername des Benutzers, der die GUI-Sitzung gestartet hat? Sie haben sich angemeldet. Wenn Sie eine dynamische Auswahl treffen möchten, können Sie ihn von abrufen

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

Beispiel:

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

oder

sudo -u $GNOME_USER notify-send "summary" "body"
S471
quelle
1
Ich denke, wenn Ihr Benutzername länger als X Zeichen ist, wird Ihr Usernma abgeschnitten: Mein Benutzername ist zum Beispiel, würde oniltonmacielaber $GNOME_USERonilton+
anzeigen
Behebung
1

Die Art und Weise, wie die Binärdatei die dbus-Adresse abruft, scheint sich in letzter Zeit geändert zu haben. Unter Ubuntu 15.04 (Vivid Vervet) mit "notify-send 0.7.6" werden die folgenden zwei Variablen benötigt:

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

Die Anweisung von 'krlmlr' wird als gut bewertet und legt die richtige Adresse fest, der Dialog wird jedoch nicht von einem Cron-Job angezeigt.

tanza
quelle
0

Wenn Ihr Skript in crontab als root ausgeführt wird, funktionieren die obigen Antworten wahrscheinlich nicht. Probieren Sie diese Funktion aus, die für mich in 16.04 gut funktioniert:

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 
}

(Quelle: https://unix.stackexchange.com/a/344377/7286 )

mivk
quelle
0

Verlassen Sie sich besser auf den dbus-sessionProzess, er sollte auf allen Systemen ausgeführt werden, auf denen er DBUS_SESSION_BUS_ADDRESSvorhanden ist.

Erstellen Sie ein Skript:

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

Mach es ausführbar:

$ chmod +x ~/notify.sh

Füge es zu crontab hinzu:

* * * * * $HOME/notify.sh
denis.peplin
quelle
0

Es hat ewig gedauert, bis die Arbeit an Ubuntu 15.10 abgeschlossen war. Es musste eine Quelle hinzugefügt werden, um die normalen Umgebungsvariablen des Benutzers zu erhalten. Meine Anzeige war: 1 aus irgendeinem Grund auch. Verwenden der ersten Ergebnis-PID der Gnome-Sitzung für die Suche nach 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
quelle
0

Ich habe das gerade mit dem Zimt-Desktop unter Ubuntu 15.10 unter Verwendung des folgenden Rezepts funktioniert:

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"

Der Trick bestand darin, zu erkennen, dass "Zimtsitzung" zu lang ist, um von pgrep gefunden zu werden:

$ 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

Ich musste auch \ grep verwenden, da mein grep mit Alias ​​versehen ist

$ alias grep
alias grep='grep -n --color=always'
John Frankland
quelle
0

Ich benutze i3 unter Ubuntu 18.04. Mein Weg, dies zu lösen, ist:

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

Herr Goferito
quelle
0

Problem durch Aufruf python3von crontab mit UTF-8Gebietsschema.

TL; DR: Präfixaufruf in crontab mit Gebietsschema wie in:

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

Siehe auch click und 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
quelle
0

Für alle crontab-Skripte, die libnotify verwenden, verwende ich Folgendes:

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

notify_user # and do other stuff

Es funktioniert auch, wenn ich cron im root-Modus verwende.

azzamsa
quelle
0

Sie benötigen lediglich den X_user und die X_userid. Ersetzen Sie beide im Befehlsbalg.

Lösung mit systemd

/etc/systemd/system/opreminder.service #Service-Datei

[Unit]
Descrption=some service to run

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


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

[Unit]
Description=Some desc


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

[Install]
WantedBy=list.timer.target

/home/jchester/bin/opreminder.sh #Das Skript

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

Es ist nicht erforderlich, sudo -u zu verwenden, wenn die Servicedatei bereits für den vorgesehenen Benutzer festgelegt wurde

Quelle: https://wiki.archlinux.org/index.php/Desktop_notifications#Usage_in_programming

Bruno
quelle