Za pomocą powiadomienia-wysyłania z cronem

32

Używam Arch Linux z KDE / Awesome WM. Próbuję zabrać się notify-senddo pracy cron.

Próbowałem ustawienia DISPLAY/ XAUTHORITYzmienne i działa notify-sendz "sudo -u", wszystko bez rezultatu.

Jestem w stanie dzwonić interaktywnie z sesji i otrzymywać powiadomienia.

FWIW, zadanie crona działa poprawnie, co zweryfikowałem przez echo rzeczy do pliku tymczasowego. To tylko „powiadomienie-wysłanie” nie działa.

Kod:

[matrix@morpheus ~]$ crontab -l
* * * * *  /home/matrix/scripts/notify.sh

[matrix@morpheus ~]$ cat /home/matrix/scripts/notify.sh
#!/bin/bash
export DISPLAY=127.0.0.1:0.0
export XAUTHORITY=/home/matrix/.Xauthority
echo "testing cron" >/tmp/crontest
sudo -u matrix /usr/bin/notify-send "hello"
echo "now tested notify-send" >>/tmp/crontest

[matrix@morpheus ~]$ cat /tmp/crontest
testing cron
now tested notify-send

[matrix@morpheus ~]$ 

Jak widać echo przed i po powiadomieniu-send działało.
Również próbowałem ustawieniaDISPLAY=:0.0

AKTUALIZACJA: Szukałem trochę więcej i stwierdziłem, że DBUS_SESSION_BUS_ADDRESS musi zostać ustawiony. Po zakodowaniu tego na podstawie wartości uzyskanej z mojej interaktywnej sesji, maleńka mała wiadomość „cześć” zaczęła pojawiać się na ekranie co minutę!

Ale catch polega na tym, że ta zmienna nie jest stała dla tego postu, więc wypróbuję nazwane rozwiązanie potoku sugerowane tam.

[matrix@morpheus ~]$ cat scripts/notify.sh
#!/bin/bash
export DISPLAY=127.0.0.1:0.0
export XAUTHORITY=/home/matrix/.Xauthority
export DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-BouFPQKgqg,guid=64b483d7678f2196e780849752e67d3c
echo "testing cron" >/tmp/crontest
/usr/bin/notify-send "hello"
echo "now tested notify-send" >>/tmp/crontest

Ponieważ cronwydaje się, że nie obsługuje wysyłania powiadomień (przynajmniej nie bezpośrednio), czy istnieje jakiś inny system powiadomień, który jest bardziej cronprzyjazny, z którego mogę korzystać?

tylko ktos
źródło
Powinno to działać, o ile widzę. Dlaczego nie dodasz a &>>/tmp/crontestdo linii wysyłania powiadomień i nie zobaczysz notify-sendżadnych komunikatów o błędach.
Graeme
Z ciekawości wypróbowałeś moje rozwiązanie? Wydaje się to o wiele prostsze i działało idealnie na moim Debianie. Proszę tylko wiedzieć, czy to jest specyficzne dla Debiana, czy nie
terdon
@terdon Wypróbowałem twoje rozwiązanie (tylko szybki test) i wydaje się, że działa na moim systemie Debian. Chciałbym wiedzieć, czy ma to ogólne zastosowanie, ponieważ jest rzeczywiście prostsze.
Marco
@Marco Jestem na LMDE (zasadniczo testy Debiana) i używam Cinnamon jako DE. Nie mogę powiedzieć, czy to działa poza tymi.
terdon
@Marco & terdon: faceci Ubuntu są w stanie to zrobić: ubuntuforums.org/showthread.php?t=1727148
justsomeone

Odpowiedzi:

29

Musisz ustawić DBUS_SESSION_BUS_ADDRESSzmienną. Domyślnie cron nie ma dostępu do zmiennej. Aby temu zaradzić, umieść gdzieś poniższy skrypt i wywołaj go, gdy użytkownik się zaloguje, na przykład używając niesamowite i run_oncefunkcji wspomnianej na wiki. Każda metoda zadziała, ponieważ nie zaszkodzi, jeśli funkcja jest wywoływana częściej niż jest to wymagane.

#!/bin/sh

touch $HOME/.dbus/Xdbus
chmod 600 $HOME/.dbus/Xdbus
env | grep DBUS_SESSION_BUS_ADDRESS > $HOME/.dbus/Xdbus
echo 'export DBUS_SESSION_BUS_ADDRESS' >> $HOME/.dbus/Xdbus

exit 0

Spowoduje to utworzenie pliku zawierającego wymaganą zmienną środowiska Dbus. Następnie w skrypcie wywoływanym przez crona importujesz zmienną, pobierając skrypt:

if [ -r "$HOME/.dbus/Xdbus" ]; then
  . "$HOME/.dbus/Xdbus"
fi

Oto odpowiedź, która wykorzystuje ten sam mechanizm.

Marco
źródło
1
Cieszę się, że jestem prawie blisko rozwiązania. Dzięki Marco, to jest miłe!
justsomeone
Świetnie, ponownie użyłem twojej odpowiedzi i dodałem tutaj bardziej szczegółowe instrukcje: askubuntu.com/a/537721/34298
rubo77
Czy nie byłoby to zagrożenie bezpieczeństwa? security.stackexchange.com/questions/71019/…
rubo77
@Gilles Jak możesz to zrobić w jednym wierszu, jak wspomniano na czacie?
rubo77
Próbowałem tylu innych odpowiedzi, w tym DBUS na Ubuntu 15.10 i nic nie działało. Ten jest prosty i działa bezbłędnie.
Bastian
16

Musisz ustawić zmienne w samym crontabie:

DISPLAY=:0.0
XAUTHORITY=/home/matrix/.Xauthority

# m h  dom mon dow   command 
* * * * *  /usr/bin/notify-send "hello"

Nie sudopotrzebne, przynajmniej nie w moim systemie.

terdon
źródło
Dzięki terdon za poświęcony czas. To wydaje się proste rozwiązanie. Niestety, nie zadziałało to dla mnie
justsomeone
@ justsomeone huh, OK, może wtedy zależeć od środowiska pulpitu.
terdon
Myślę, że ma to coś wspólnego z dystrybucją lub środowiskiem graficznym. Dla użytkowników Ubuntu proste rozwiązania wydają się działać dobrze z tego, co widziałem na forach internetowych.
justsomeone
@ justsomeone Jestem na Debianie (LMDE) używając Cinnamon jako DE. Może to mieć coś wspólnego ze sposobem uruchamiania X lub systemem powiadomień używanym przez DE, dunno.
terdon
Potwierdzono, że działa na Ubuntu 14.04 / 14.10. Z GNOME i Unity.
Jordon Bedwell
8

Najbezpieczniejszym sposobem na uzyskanie zmiennych środowiskowych związanych z sesją X jest pobranie ich ze środowiska procesu użytkownika zalogowanego do X. Oto adaptacja skryptu, którego używam do tego samego celu (chociaż DBUS_SESSION_BUS_ADDRESS nie robi wydaje mi się to problemem dla Debiana):

X=Xorg                   # works for the given X command
copy_envs="DISPLAY XAUTHORITY DBUS_SESSION_BUS_ADDRESS"

tty=$(ps h -o tty -C $X | head -1)
[ -z "$tty" ] && exit 1

# calling who with LANG empty ensures a consistent date format
who_line=$(LANG= who -u | grep "^[^ ]\+[ ]\+$tty")

x_user=$(echo $who_line | cut -d ' ' -f 1)  # the user associated with the tty
pid=$(echo $who_line | cut -d ' ' -f 7)     # the user's logon process

for env_name in $copy_envs
do
  # if the variable is not set in the process environment, ensure it does not remain exported here
  unset "$env_name"

  # use the same line as is in the environ file to export the variable
  export "$(grep -az "^$env_name=" /proc/$pid/environ)" >/dev/null
done

sudo -u "$x_user" notify-send "hello"

To wysyła wiadomość do pierwszego znalezionego użytkownika X, chociaż można dodać pętlę, aby wysłać go do wszystkich użytkowników.

Aktualizacja

Wygląda na to, że aktualizacje formatu utmp powodują whowydrukowanie wyświetlacza zamiast tty w drugiej kolumnie. To faktycznie sprawia, że ​​jest łatwiej, wcześniej drukował tylko wyświetlacz w komentarzu na końcu i zdecydowałem, że nie jest bezpiecznie polegać na oryginalnej odpowiedzi. Jeśli tak jest, spróbuj tego:

X=Xorg                   # works for the given X command
copy_envs="DISPLAY XAUTHORITY DBUS_SESSION_BUS_ADDRESS"

# calling who with LANG empty ensures a consistent date format
who_line=$(LANG= who -u | awk '$2 ~ ":[0-9]"')

x_user=$(echo $who_line | cut -d ' ' -f 1)  # the user associated with the tty
pid=$(echo $who_line | cut -d ' ' -f 7)     # the user's logon process

for env_name in $copy_envs
do
  # if the variable is not set in the process environment, ensure it does not remain exported here
  unset "$env_name"

  # use the same line as is in the environ file to export the variable
  export "$(grep -az "^$env_name=" /proc/$pid/environ)" >/dev/null
done

sudo -u "$x_user" notify-send "hello"
Graeme
źródło
To nie działa dla mnie w Trusty, ponieważ w poleceniu nie ma wydrukowanego tty who_line. Wyjście wygląda jak me :0 2015-09-23 10:40 ? 17234.
blujay,
1
@blujay, zaktualizowano.
Graeme,
Dzięki, to działa. Jednak, jak napisałem w osobnej odpowiedzi, istnieje jeszcze prostsze rozwiązanie.
blujay,
@blujay tak, to była próba przenośnej odpowiedzi. Nie jestem jednak pewien, czy to naprawdę możliwe, ale w większości przypadków powinno nadal działać.
Graeme,
2

Ten liner działał dla mnie w Manjaro z Cronie:

# Note: "1000" would be your user id, the output of... "id -u <username>" 
10 * * * * pj DISPLAY=:0 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus notify-send 'Hello world!' 'This is an example notification.'

Bez bardzo brzydkiego DBUS_blah_blah w ogóle nie działa. Uznałem również za journalctl -xb -u croniepomocny. Nie znam jeszcze Cronie, ale utworzyłem „crontab” jako /etc/cron.d/mycronjobsi nie jestem pewien, czy ta nazwa pliku jest wymagana, czy tylko czyta wszystko w katalogu cron.d.

Znalazłem rozwiązanie tutaj https://wiki.archlinux.org/index.php/Desktop_notifications

PJ Brunet
źródło
2

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
1

Jest to wystarczające, aby powiadomienie-wysyłanie działało dla mnie w cronjob na Ubuntu Trusty:

#!/bin/bash
export DISPLAY=$(who -u | awk  '/\s:[0-9]\s/ {print $2}')

Po prostu eksportuje DISPLAYużytkownika, dla którego działa cronjob. Działa dla mnie bez ustawiania XAUTHORITYlub DBUS_SESSION_BUS_ADDRESS.

blujay
źródło
1
Działa również na Ubuntu 16.04. W rzeczywistości mam crona uruchamiającego skrypt Perla, który system () jest skryptem bash, który uruchamia inny skrypt Perla, który wykonuje system („powiadom-wyślij ...”). Dodanie polecenia eksportu do skryptu bash zmodyfikowało środowisko dla tego skryptu, który ostatni skrypt Perla odziedziczył i udostępnił systemowi („powiadom-wyślij ...”). Dobry znaleźć blujay!
Tim
1

Dla tych z Linuksa, którzy lubią instalować pakiety Pythona, właśnie wydałem program bezgłowy typu „wyślij-wyślij ”, który działa dla mnie dobrze. Wyszukuje /procwymaganą nazwę użytkownika i zmienne środowiskowe, a następnie uruchamia się notify-sendz tymi zmiennymi (w sudorazie potrzeby przełączy się na wymaganego użytkownika).

Xolox
źródło
1

Możesz także zrobić skrypt:

#!/usr/bin/env bash
runuser -l [yourusername] -c 'DISPLAY=:0 notify-send "hey there user"'

Następnie uruchom go sudo. Ponieważ jednak crontab -ewszystkie komendy są uruchamiane przez użytkownika, który go utworzył, wystarczy, że wywołane bez sudo:

#!/usr/bin/env bash
DISPLAY=:0 notify-send "hey there user"

Przynajmniej tak dla mnie. Wszystko wydaje się zależeć od konfiguracji środowiska.

użytkownik 1112789
źródło
0

Używam tego skryptu w cronie, aby publikować MPD teraz grającego na Twitterze co godzinę

#!/bin/bash
export DISPLAY=":0.0"
msg=$(mpc current -h 192.168.1.33)
twitter set "#MPD Server nowplaying $msg :  http://cirrus.turtil.net:9001"
#ttytter -status="#MPD Server nowplaying $msg. http://cirrus.turtil.net:9001"

exit 

podobny skrypt wykorzystujący powiadomienie-wysyłanie

#!/bin/bash
export DISPLAY=":0.0"
notify-send -i ~/.icons/48arch.png 'OS- Archlinux x86_64 : DWM Window Manager' 'Installed on Sun Apr 21 2013 at 18:17:22' 
exit

możesz mieć problemy, ponieważ KDE używa własnego IIRC powiadomień.

cirrus
źródło
0

Tyle ile jest warte....

Musiałem użyć WSZYSTKICH następujących elementów na Debian Jessie, aby to zadziałało ...

export DISPLAY=:0.0
export HOME=/home/$user
source "$HOME/.dbus/session-bus/*-0"

Pozostawienie któregokolwiek z nich spowodowało, że przestał działać.

BenJ
źródło
Ta ostatnia linia nie zrobi nic, jak tu napisano, ponieważ *-0w twoim session-buskatalogu nie będzie żadnego pliku wywoływanego dosłownie . Mogłeś mieć na myśli source "$HOME"/.dbus/session-bus/*-0.
roaima,
0

Korzystanie z sudo:

sudo -u $currentxuser notify-send $message

Wskazówka :

Możemy uzyskać bieżącego użytkownika x za pomocą tego polecenia

ps auxw | grep -i screen | grep -v grep | cut -f 1 -d ' '

Dodatkowo...

currentxuser=$(ps auxw | grep -i screen | grep -v grep | cut -f 1 -d ' ')
echo $currentxuser

Dobrze wiedzieć :

Cron działający pod rootem nie ma dostępu do x, więc wszystkie polecenia GUI nie będą wyświetlane, jednym prostym rozwiązaniem jest dodanie roota do uprawnionego x użytkownika dla bieżącego x użytkownika za pomocą tego polecenia

z powłoki użytkownika x

xhost local:root

lub

sudo -u $currentxuser xhost local:root
intika
źródło
-1

Oto mniej skomplikowany skrypt niż ten, który zapewnił Graeme. Jego scenariusz nie działał dla mnie, $who_linezawsze był pusty. Mój skrypt nie marnuje dużo czasu na znalezienie procesu. Zamiast tego po prostu próbuje wszystkich i wybiera ostatnią znalezioną użyteczną wartość. Używam Xubuntu 14.04 i mam kilka kontenerów LXC, które prawdopodobnie mylą tego rodzaju skrypty.

env="$(
  ps -C init -o uid,pid | while read u p; do
    [ "$u" = "`id -u`" ] || continue
    grep -az '^DBUS_SESSION_BUS_ADDRESS=' /proc/$p/environ | xargs -0
  done | tail -1
)"

export "$env"

notify-send "test"
Daniel Alder
źródło
To nie działa dla mnie w Trusty, ponieważ środowisko procesu Xorg nie ma DBUS_SESSION_BUS_ADDRESS. Mogę to pobrać z moich powłok, ale nie z procesu Xorga.
blujay,