Usando o Notificar-Enviar com Cron

32

Estou usando o Arch Linux com o KDE / Awesome WM. Eu estou tentando notify-sendtrabalhar cron.

Eu tentei definir DISPLAY/ XAUTHORITYvariáveis ​​e executando notify-sendcom "sudo -u", tudo sem resultado.

Consigo ligar para notificar-enviar interativamente a partir da sessão e receber notificações.

FWIW, o trabalho cron está sendo executado corretamente, o que eu verifiquei ecoando coisas para um arquivo temporário. É apenas o "envio de notificação" que não funciona.

Código:

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

Como você pode ver, o eco antes e depois do envio de notificação funcionou.
Também tentei configurarDISPLAY=:0.0

ATUALIZAÇÃO: pesquisei um pouco mais e descobri que DBUS_SESSION_BUS_ADDRESS precisa ser definido. E depois de codificar isso usando o valor que recebi da minha sessão interativa, a pequena mensagem de "olá" começou a aparecer na tela a cada minuto!

Mas o problema é que essa variável não é permanente por esse post, então tentarei a solução de pipe nomeada sugerida lá.

[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

Como cronnão parece oferecer suporte ao envio de notificação (pelo menos não diretamente), existe algum outro sistema de notificação mais cronamigável que eu possa usar?

apenas alguém
fonte
Isso deve funcionar tanto quanto eu posso ver. Por que você não adiciona um &>>/tmp/crontestà linha de notificação de envio e vê se há notify-sendalguma mensagem de erro.
Graeme
Por curiosidade, você tentou minha solução? Parece muito mais simples e funcionou perfeitamente no meu Debian. Estou pedindo apenas para saber se o Debian é específico ou não
terdon
@terdon Eu tentei sua solução (apenas um teste rápido) e parece funcionar no meu sistema Debian. Gostaria de saber se é geralmente aplicável, uma vez que é realmente mais simples.
Marco
@Marco Estou no LMDE (essencialmente testes Debian) e estou usando o Cinnamon como DE. Não posso dizer se funciona além desses.
terdon
@Marco & terdon: Ubuntu caras são capazes de fazê-lo: ubuntuforums.org/showthread.php?t=1727148
justsomeone

Respostas:

29

Você precisa definir a DBUS_SESSION_BUS_ADDRESSvariável. Por padrão, o cron não tem acesso à variável. Para remediar isso, coloque o seguinte script em algum lugar e chame-o quando o usuário efetuar login, por exemplo, usando awesome e a run_oncefunção mencionada no wiki. Qualquer método serve, pois não prejudica se a função for chamada com mais frequência do que o necessário.

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

Isso cria um arquivo contendo a variável de ambiente Dbus necessária. Em seguida, no script chamado pelo cron, você importa a variável, fornecendo o script:

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

Aqui está uma resposta que usa o mesmo mecanismo.

Marco
fonte
1
Fico feliz em ver que eu estava quase perto da solução. Obrigado Marco, isso é legal!
precisa saber é o seguinte
Ótimo, eu reutilizado sua resposta e acrescentou algumas instruções mais detalhadas aqui: askubuntu.com/a/537721/34298
rubo77
Isso não seria um risco de segurança? security.stackexchange.com/questions/71019/...
rubo77
@Gilles Como você pôde fazer isso em uma linha como você mencionou no chat?
rubo77
Eu tentei muitas outras respostas que não incluem o DBUS no ubuntu 15.10 e nada funcionou. Essa é simples e funciona perfeitamente.
bastian
16

Você precisa definir as variáveis ​​no próprio crontab:

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

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

Não é sudonecessário, pelo menos não no meu sistema.

terdon
fonte
Obrigado Terdon pelo seu tempo. Esta parece ser uma solução simples. Infelizmente, isso não funcionou para mim,
justsomeone
@justsomeone huh, OK, pode depender do ambiente da área de trabalho.
terdon
Eu acho que isso tem algo a ver com distro ou ambiente de desktop. Para usuários do Ubuntu, as soluções diretas parecem funcionar bem com o que eu vi nos fóruns online.
justsomeone
@justsomeone Estou no Debian (LMDE) usando Cinnamon como DE. Pode ter algo a ver com a forma como o X é iniciado ou com o sistema de notificações usado pelo DE, não sei.
terdon
Confirmado que funciona no Ubuntu 14.04 / 14.10. Com o GNOME e o Unity.
precisa saber é o seguinte
8

A maneira mais segura de obter variáveis ​​ambientais relacionadas à sessão X é obtê-las do ambiente de um processo do usuário conectado ao X. Aqui está uma adaptação do script que eu uso exatamente para o mesmo objetivo (embora DBUS_SESSION_BUS_ADDRESS não tenha ' parece ser um problema para mim no 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"

Isso envia uma mensagem para o primeiro usuário X encontrado, embora você possa adicionar um loop para enviá-lo a todos os usuários.

Atualizar

Parece que as atualizações no formato utmp causam whoa impressão de uma exibição em vez de um tty em sua segunda coluna. Isso na verdade facilita as coisas, antes ele apenas imprimia a exibição no comentário no final e eu decidi que não era seguro confiar na resposta original. Se for esse o caso, tente o seguinte:

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
fonte
Isso não funciona para mim no Trusty, porque não há tty impresso no who_linecomando. A saída parece me :0 2015-09-23 10:40 ? 17234.
Bloqueios # 3/15
1
@blujay, atualizado.
Graeme
Obrigado, isso funciona. No entanto, como eu postei em uma resposta separada, há uma solução ainda mais simples.
blujay
@ Blujay sim, esta foi uma tentativa de uma resposta portátil. Não tenho certeza se isso é realmente possível, mas ainda deve funcionar na maioria dos casos.
Graeme
2

Essa frase só funcionou para mim em Manjaro com 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.'

Sem o muito feio DBUS_blah_blah, ele não funciona. Eu também achei journalctl -xb -u cronieútil. Ainda não estou familiarizado com o Cronie, mas criei o meu "crontab" /etc/cron.d/mycronjobse não tenho certeza se esse nome de arquivo é necessário ou se apenas lê tudo no diretório cron.d.

Encontrei a solução aqui https://wiki.archlinux.org/index.php/Desktop_notifications

PJ Brunet
fonte
2

Eu uso o i3 no Ubuntu 18.04. Minha maneira de resolver isso é:

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

Mr. Goferito
fonte
1

Isso é suficiente para fazer com que o envio de notificação funcione para mim em um cronjob no Ubuntu Trusty:

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

Ele simplesmente exporta DISPLAYpara o usuário em que o cronjob está sendo executado. Funciona para mim sem definir XAUTHORITYou DBUS_SESSION_BUS_ADDRESS.

Blujay
fonte
1
Também funciona no Ubuntu 16.04. Na verdade, tenho o cron iniciando um script Perl, que system () é um script bash, que lança um script Perl diferente, que executa um sistema ("notificação-envio ..."). A adição do comando export ao script bash modificou o ambiente para esse script, que o último script Perl herdou e disponibilizou para o sistema ("notificação-envio ..."). Bom encontrar blujay!
Tim
1

Para quem está confortável com a instalação de pacotes Python no Linux, acabei de lançar um programa de notificação-envio-sem-cabeça que está funcionando bem para mim. Ele procura /proco nome de usuário necessário e as variáveis ​​de ambiente e, em seguida, executa notify-sendcom essas variáveis ​​(será usado sudopara alternar para o usuário necessário, se necessário).

xolox
fonte
1

Você também pode criar um script:

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

Em seguida, execute-o com sudo. No entanto, como crontab -eexecuta todos os comandos com o usuário que o criou, o seguinte deve ser suficiente quando chamado sem sudo:

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

Pelo menos faz para mim. Tudo parece depender da configuração do ambiente.

user1112789
fonte
0

Eu uso esse script no cron para postar MPD agora tocando no twitter a cada hora

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

script semelhante usando o envio de notificação

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

você pode estar tendo problemas, já que o KDE usa seu próprio notify-deamon IIRC.

cirro
fonte
0

Por que vale a pena ....

Eu tive que usar TODOS os itens a seguir no Debian Jessie para fazer isso funcionar ...

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

Deixar de fora qualquer um deles fez com que parasse de funcionar.

BenJ
fonte
Essa última linha não fará nada como está escrito aqui, porque não haverá nenhum arquivo literalmente chamado *-0em seu session-busdiretório. Você pode ter pensado source "$HOME"/.dbus/session-bus/*-0.
roaima
0

Usando o sudo:

sudo -u $currentxuser notify-send $message

Gorjeta :

Podemos obter o usuário x atual por este comando

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

Além do que, além do mais...

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

Bom saber :

Cron executando sob root não tem acesso a x, portanto, todos os comandos gui não serão exibidos; uma solução simples é adicionar root ao usuário x autorizado para o usuário x atual com este comando

do shell do usuário x

xhost local:root

ou

sudo -u $currentxuser xhost local:root
intika
fonte
-1

Aqui está um script menos complexo do que o Graeme forneceu. Seu roteiro não funcionou para mim, $who_lineestava sempre vazio. Meu script não perde muito tempo para encontrar um processo. Em vez disso, apenas tenta tudo e escolhe o último valor útil encontrado. Estou executando o xubuntu 14.04 e tenho alguns contêineres lxc em execução que provavelmente confundem esse tipo de script.

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
fonte
Isso não funciona para mim no Trusty, porque o ambiente do processo Xorg não tem DBUS_SESSION_BUS_ADDRESS. Consigo obtê-lo das minhas conchas, mas não do processo Xorg.
Bloqueios # 3/15