Использование notify-send с cron

32

Я использую Arch Linux с KDE / Awesome WM. Я пытаюсь заставить notify-sendработать cron.

Я попытался установить DISPLAY/ XAUTHORITYпеременные и работает notify-sendс "sudo -u", все безрезультатно.

Я могу звонить, уведомлять-отправлять в интерактивном режиме с сессии и получать уведомления.

FWIW, задание cron работает нормально, что я проверял, выводя вещи во временный файл. Это просто «уведомить-отправить», которая не работает.

Код:

[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 ~]$ 

Как вы можете видеть эхо до и после уведомления-отправки сработало.
Также я попробовал установкуDISPLAY=:0.0

ОБНОВЛЕНИЕ: я искал немного больше и обнаружил, что DBUS_SESSION_BUS_ADDRESS должен быть установлен. И после того, как я жестко запрограммировал это, используя значение, которое я получил от моего интерактивного сеанса, крошечное маленькое «привет» сообщение начало появляться на экране каждую минуту!

Но уловка в том, что эта переменная не является постоянной для каждого поста, поэтому я попробую решение с именованным каналом, предложенное там.

[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

Поскольку cron, похоже, не поддерживается отправка уведомлений (по крайней мере, напрямую), существует ли какая-то другая система уведомлений, более cronудобная для использования?

justsomeone
источник
Это должно работать, насколько я вижу. Почему бы вам не добавить &>>/tmp/crontestв строку отправки уведомлений и посмотреть, notify-sendдает ли какие-либо сообщения об ошибках.
Грэм
Из любопытства, вы пробовали мое решение? Кажется, это намного проще и отлично работает на моем Debian. Я прошу просто узнать, специфичен ли он для Debian или нет
terdon
@terdon Я попробовал ваше решение (просто быстрый тест), и, похоже, оно работает на моей системе Debian. Я хотел бы знать, если это вообще применимо, так как это действительно проще.
Марко
@Marco Я нахожусь на LMDE (по сути, тестирование Debian) и использую Cinnamon в качестве DE. Не могу сказать вам, если это работает за их пределами.
Terdon
@Marco & terdon: Ребята из Ubuntu могут сделать это: ubuntuforums.org/showthread.php?t=1727148
justsomeone

Ответы:

29

Вам нужно установить DBUS_SESSION_BUS_ADDRESSпеременную. По умолчанию cron не имеет доступа к переменной. Чтобы исправить это, поместите следующий скрипт куда-нибудь и вызывайте его, когда пользователь входит в систему, например, используя awesome и run_onceфункцию, упомянутую в вики. Подойдет любой метод, поскольку он не причиняет вреда, если функция вызывается чаще, чем требуется.

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

Это создает файл, содержащий необходимую переменную среды Dbus. Затем в скрипте, вызванном cron, вы импортируете переменную, используя скрипт:

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

Вот ответ, который использует тот же механизм.

Marco
источник
1
Рад видеть, что я был почти рядом с решением. Спасибо Марко, это здорово!
justsomeone
Отлично, я повторно использовал ваш ответ и добавил несколько более подробных инструкций здесь: askubuntu.com/a/537721/34298
rubo77
Не будет ли это угрозой безопасности? security.stackexchange.com/questions/71019/...
rubo77
@ Жиль Как ты мог сделать это в одной строке, как ты упомянул в чате?
rubo77
Я пробовал так много других ответов, не считая DBUS на Ubuntu 15.10, и ничего не получалось. Это просто и работает без нареканий.
Бастиан
16

Вам нужно установить переменные в самом crontab:

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

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

Нет sudoнеобходимости, по крайней мере, не в моей системе.

Тердон
источник
Спасибо Тердон за ваше время. Это кажется простым решением. К сожалению, это не сработало для меня,
justsomeone
@justsomeone да, ладно, может зависеть от окружения рабочего стола.
Terdon
Я думаю, что это как-то связано с дистрибутивом или Desktop Environment. Для пользователей Ubuntu прямые решения, кажется, хорошо работают из того, что я видел на онлайн-форумах.
justsomeone
@justsomeone Я в Debian (LMDE), используя Cinnamon в качестве DE. Может быть, это связано с тем, как запускается X, или с системой уведомлений, используемой DE, не знаю.
Terdon
Подтвердил, что работает на Ubuntu 14.04 / 14.10. С GNOME и Unity.
Джордон Бедвелл
8

Самый безопасный способ получить переменные среды, связанные с сеансом X, - это получить их из среды процесса пользователя, вошедшего в X. Вот адаптация сценария, который я использую для той же цели (хотя DBUS_SESSION_BUS_ADDRESS не ' мне кажется, это проблема для меня в Debian):

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"

Это отправляет сообщение первому найденному пользователю X, хотя вы можете добавить цикл, чтобы отправить его всем пользователям.

Обновить

Кажется, что обновления в формате utmp приводят whoк выводу дисплея вместо tty во втором столбце. Это на самом деле делает вещи проще, ранее это только печатало отображение в комментарии в конце, и я решил, что на исходный ответ полагаться не стоит. Если это так, попробуйте это:

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
источник
На Trusty у меня это не работает, потому что в who_lineкоманде нет tty . Выход выглядит так me :0 2015-09-23 10:40 ? 17234.
Блюджей
1
@blujay, обновлено.
Грэм
Спасибо, это работает. Однако, как я написал в отдельном ответе, есть еще более простое решение.
Блюджей
@blujay да, это была попытка портативного ответа. Не уверен, что это действительно возможно, но это все равно должно работать в большинстве случаев.
Грэм
2

Этот однострочник работал для меня в Манджаро с Крони:

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

Без очень уродливого DBUS_blah_blah это не работает вообще. Я также нашел journalctl -xb -u cronieполезным. Я еще не знаком с Cronie, но создал свой "crontab" как /etc/cron.d/mycronjobsи я не уверен, требуется ли это имя файла, или он просто читает все в каталоге cron.d.

Я нашел решение здесь https://wiki.archlinux.org/index.php/Desktop_notifications

PJ Brunet
источник
2

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

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

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

Этого достаточно, чтобы заставить меня отправлять уведомления-отправлять в Cronjob на Ubuntu Trusty:

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

Он просто экспортирует DISPLAYдля пользователя, от которого выполняется cronjob. У меня работает без настройки XAUTHORITYили DBUS_SESSION_BUS_ADDRESS.

blujay
источник
1
Работает и на Ubuntu 16.04. На самом деле у меня есть cron, запускающий скрипт Perl, который system () является скриптом bash, который запускает другой скрипт Perl, который выполняет систему («notify-send ...»). Добавление команды экспорта в сценарий bash изменило среду для этого сценария, который последний сценарий Perl затем унаследовал и сделал доступным для системы («notify-send ...»). Хорошая находка блюджай!
Тим
1

Для тех в Linux, кому удобно устанавливать пакеты Python, я только что выпустил программу notify-send-headless, которая хорошо работает для меня. Он ищет /procтребуемые переменные имени пользователя и среды, а затем запускается notify-sendс этими переменными (при необходимости он sudoпереключается на нужного пользователя).

xolox
источник
1

Вы также можете сделать скрипт:

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

Тогда запустите это с sudo. Однако, поскольку crontab -eвсе команды выполняются пользователем, который его создал, при вызове безsudo :

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

По крайней мере, это для меня. Кажется, все зависит от конфигурации среды.

user1112789
источник
0

Я использую этот скрипт в cron для публикации MPD, теперь играю в твиттере каждый час

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

аналогичный скрипт с использованием notify-send

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

возможно, у вас возникли проблемы, поскольку KDE использует собственный IIRC для уведомлений.

усик
источник
0

За что его стоит ....

Мне пришлось использовать ВСЕ из следующего на Debian Jessie, чтобы заставить это работать ...

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

Отсутствие любого из них привело к тому, что оно перестало работать.

Benj
источник
Эта последняя строка не будет делать ничего, как написано здесь, потому что *-0в вашем session-busкаталоге не будет буквально вызванного файла . Вы могли иметь в виду source "$HOME"/.dbus/session-bus/*-0.
Роайма
0

Использование sudo:

sudo -u $currentxuser notify-send $message

Чаевые :

С помощью этой команды мы можем получить текущего пользователя x

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

К тому же...

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

Хорошо знать :

Cron, работающий под root, не имеет доступа к x, поэтому все команды gui не будут отображаться, одно простое решение - добавить root к авторизованному пользователю x для текущего пользователя x с помощью этой команды.

из пользовательской оболочки x

xhost local:root

или

sudo -u $currentxuser xhost local:root
intika
источник
-1

Вот менее сложный сценарий, чем тот, что предоставил Грэм. Его сценарий не работал для меня, $who_lineвсегда был пустым. Мой сценарий не тратит столько времени на поиск процесса. Вместо этого он просто пробует все и выбирает последнее найденное полезное значение. Я использую xubuntu 14.04 и у меня работает несколько контейнеров lxc, которые, вероятно, запутывают этот вид сценариев.

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"
Даниэль Алдер
источник
Это не работает для меня на Trusty, потому что среда процесса Xorg не имеет DBUS_SESSION_BUS_ADDRESS. Я могу получить это из своих оболочек, но не из процесса Xorg.
Блюджей