Notify-send não funciona no crontab


44

Eu criei um script que deveria me notificar quando houver um novo capítulo de mangá que estou lendo. Eu usei o comando notificar-enviar para fazer isso. O programa funciona quando estou tentando executá-lo no terminal. A notificação está sendo exibida. No entanto, quando coloquei isso no meu crontab, a notificação não aparece. Tenho certeza de que o programa está sendo executado desde que criei um arquivo para mim. O arquivo foi criado, mas a notificação não foi exibida.

Aqui está o meu script

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

E aqui está o que eu escrevi no meu crontab

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

Apenas um lembrete, todos os comandos no crontab precisam ter seu caminho na frente deles enquanto são executados como raiz. Colocar script e linha no crontab iria ajudar de outra forma estamos apenas adivinhando o seu problema
Meer Borg

Sim, desculpe-me. Eu apenas fiz.
User158335

Esta é uma má ideia. As notificações são uma coisa "GUI", o cron é uma coisa "console". Não há garantia de que a lib-notify poderá encontrar uma maneira de exibir a mensagem. Em vez disso, você deve considerar enviar dados para o stdout e deixar que as mensagens do cron cuidem do envio das informações. Normalmente, um email é enviado.
Coteyr #

2
Em alguns casos, definindo a variável de exibir até pode ajudar, bem como, por exemplo: export DISPLAY=:0.
Glutanimate

1
Pois 16.04, este funcionou para mim */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

Respostas:


18

Os comandos precisam fazer referência à sua localização. Então notify-sendprecisa ser/usr/bin/notify-send

Todos os comandos precisam ter seu caminho completo.

Use o whereis notify-sendcomando para ver onde seus comandos "vivem"


2
Isso inclui cat, wget, if, let, grep, echo, etc?
User158335

7
Pelo menos no meu sistema, notify-sendestá no PATHmesmo nível para um trabalho cron. Veja minha resposta abaixo.
precisa

2
Não é a solução para o Ubuntu 17.04. Veja askubuntu.com/a/472769/413683 e askubuntu.com/a/834479/413683 .
Mateusz Piotrowski

2
Este não é o problema. O problema é que os scripts cron não são executados na sessão do usuário e não têm conceito do ambiente da sessão de login do usuário. Como a notificação de envio requer conexão com um barramento de sessão do dbus para enviar a notificação, não importa de que caminho o binário é chamado, quando não se conectar ao barramento de sessão correto.
Doobey 26/10

2
Esta não é a resposta. Claro, se o executável não puder ser localizado, ele não será executado, MAS: 1. o send-notification está no PATH, portanto ele estará localizado 2. mesmo que não estivesse no PATH, e você especificar o caminho completo não funciona, porque na verdade DBUS_SESSION_BUS_ADDRESS deve ser definido para o envio de notificação. E a resposta correta é de kmir.
Kris Jace

31

As coisas parecem diferentes no 13.04, pelo menos no Gnome Shell.

Primeiro, é isso que é envimpresso quando executado a partir zzyxyda tarefa cron do usuário (não da raiz):

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

Para começar notify-senda trabalhar, parece ser necessário definir a DBUS_SESSION_BUS_ADDRESSvariável de ambiente, conforme comentário do DahitiF no ubuntuforums.org. Anexe apenas o seguinte à descrição do seu trabalho:

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

Não parece ser necessário definir DISPLAY.


4
Obrigado, é isso que finalmente funcionou para mim. No Xubuntu, você precisa mudar gnome-sessionpara xfce4-session.
shrx

Esta é a única resposta para trabalhar para 14.04, junto com a dica óbvia da aceita.
Wtower

1
Eu não tinha gnome-sessione usei em gnome-shellvez disso (tenha cuidado, há também um gnome-shell-calendar-servermodo pgrepque receberá 2 pids). Eu também precisava DISPLAY=:0porque eu estava usando duas telas físicas e não foi definido. Obrigado!
soyuka 27/05

Se você estiver usando o Openbox (como no CB ++), troque openboxpor gnome-session.
ACK_stoverflow

ESTA é a resposta correta, e a resposta aceita nem mesmo está correta, ela fala sobre a variável DISPLAY que nem é necessária nem resolve o problema.
Kris Jace

24

O comando notify-sendnão mostraria a mensagem na tela quando iniciado pelo cron. Basta adicionar a exibição de destino na parte superior do seu script, por exemplo:

export DISPLAY=:0

Isto é o que eu tive que fazer em 14.10 também. Caso contrário, eu receberia este erro #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:
Joelmob

1
Este. E use echo $DISPLAYem um terminal para garantir que seu monitor seja realmente :0(normalmente é, mas nem sempre).
Mark

Só isso funcionou para mim, eu estou usando Linux Mint
harendra Singh

5

Pelo menos para o Ubuntu 14.04, a resposta do klrmr acima é a resposta correta. Não parece ser necessário definir DISPLAY ou articular caminhos completos para envio de notificação ou qualquer outra coisa normalmente em $ PATH.

Abaixo está um script cron que estou usando para desligar uma máquina virtual quando o estado da bateria de um laptop fica muito baixo. A configuração da linha DBUS_SESSION_BUS_ADDRESS na resposta do klrmr acima é a modificação que finalmente conseguiu que os avisos funcionassem corretamente.

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

Esta foi a solução que funcionou perfeitamente para mim também. Acabei de adicionar a linha "eval ..." ao meu script que corro do crontab - agora funciona perfeitamente
Mtl Dev

2

No meu caso com o ubuntu 16.04, qualquer caminho explícito era necessário, resolvo o problema apenas adicionando

DISPLAY =: 0

nas primeiras linhas do crontab, antes de ligar para notificar-enviar.


Essa é a única coisa necessária para que ele funcione no 16.04.
Jonathan Landrum

1

O primeiro culpado é o seu arquivo crontab, você também precisa mencionar o nome de usuário com o qual o script deve ser executado, melhor mantê-lo como root

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

e, em seguida, você deve usar o nome de usuário do usuário da GUI dentro do script e anexá-lo previamente para notificar-enviar com "sudo ou su" para executar o comando como um usuário que possui a GUI

exemplo:

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

ou

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

onde gnome_user_nameé o nome de usuário do usuário que iniciou a sessão da GUI, foi você quem efetuou login e, se quiser torná-la uma escolha dinâmica, pode obtê-lo em

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

exemplo:

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

ou

sudo -u $GNOME_USER notify-send "summary" "body"

1
Eu acho que quando seu nome de usuário é mais de caracteres X, seu usernma é truncado: Por exemplo, o meu nome é oniltonmaciel, mas $GNOME_USERiria mostrar onilton+(não funciona)
Onilton Maciel

fixa-lo com melhor domínio
S471

1

A maneira como o binário recupera o endereço dbus parece ter mudado ultimamente. No Ubuntu 15.04 (Vivid Vervet) com "notify-send 0.7.6", são necessárias as seguintes duas variáveis:

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

A instrução 'krlmlr' avalia bem e define o endereço correto, mas a caixa de diálogo não aparece em um trabalho cron.


0

Se o seu script no crontab estiver sendo executado como root, as respostas acima provavelmente não funcionarão. Tente esta função, que funciona bem para mim no 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 
}

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


0

Melhor confiar no dbus-sessionprocesso, ele deve estar em execução em todos os sistemas onde DBUS_SESSION_BUS_ADDRESSestá presente.

Crie um script:

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

Torne executável:

$ chmod +x ~/notify.sh

Adicione-o ao crontab:

* * * * * $HOME/notify.sh

0

Demorou uma eternidade para fazer o trabalho no ubuntu 15.10. Tinha que adicionar uma fonte para obter os usuários normais. minha exibição foi: 1 por algum motivo também. Usando os primeiros resultados do gnome-session, pid para a pesquisa 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)"

0

Acabei de fazer isso funcionar com a área de trabalho de canela no Ubuntu 15.10, usando a seguinte receita:

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"

O truque era perceber que a "sessão de canela" é muito longa para o pgrep encontrar:

$ 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

Eu também tive que usar \ grep porque meu grep é alias para

$ alias grep
alias grep='grep -n --color=always'

0

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


0

Problema causado pela chamada python3no crontab com UTF-8localidade.

TL; DR: chamada de prefixo no crontab com localidade como em:

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

Veja também click e 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

0

Para todos os scripts crontab que usam libnotify, eu uso este:

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

notify_user # and do other stuff

Funciona mesmo se eu usar o cron no modo raiz.


0

Tudo o que você precisa é do X_user e do X_userid. Substitua ambos no comando abaixo.

Solução com systemd

/etc/systemd/system/opreminder.service # Arquivo de serviço

[Unit]
Descrption=some service to run

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


Arquivo /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 #O script

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

Não há necessidade de usar sudo -u se o arquivo de serviço já estiver definido com o usuário pretendido

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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.