crontab에서 알림 전송이 작동하지 않습니다


44

읽고있는 새로운 만화 장이있을 때 알려 주어야하는 스크립트를 만들었습니다. 이를 위해 notify-send 명령을 사용했습니다. 터미널에서 프로그램을 실행하려고하면 프로그램이 작동합니다. 알림이 표시됩니다. 그러나 이것을 crontab에 배치하면 알림이 표시되지 않습니다. 나에게 파일을 만들기 위해 만든 이후 프로그램이 실행되고 있다고 확신합니다. 파일이 생성되었지만 알림이 표시되지 않았습니다.

여기 내 스크립트가 있습니다

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

그리고 여기 내 crontab에 쓴 것이 있습니다

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

간단히 말해, crontab의 모든 명령은 루트로 실행될 때 앞에 경로가 있어야합니다. crontab에 스크립트와 줄을 첨부하면 문제를 추측하는 데 도움이됩니다.
Meer Borg

그래, 미안 난 그냥했다.
user158335

이것은 나쁜 생각입니다. 알림은 "GUI"이고 cron은 "콘솔"입니다. lib-notify가 메시지를 표시하는 방법을 찾을 수있는 사람은 없습니다. 대신 stdout으로 데이터를 전송하고 cron의 메시징이 정보를 보내도록해야합니다. 일반적으로 이메일이 전송됩니다.
coteyr

2
경우에 따라 DISPLAY 변수를 설정하는 것도 도움이 될 수 있습니다 export DISPLAY=:0. 예 : .
Glutanimate

1
를 위해 16.04, 이것은 나를 위해 일했다 */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

답변:


18

명령은 해당 위치를 참조해야합니다. 그래서 notify-send할 필요가/usr/bin/notify-send

모든 명령에는 전체 경로가 있어야합니다.

whereis notify-send명령을 사용하여 명령이 "라이브"된 곳을 확인


2
cat, wget, if, let, grep, echo 등이 포함됩니까?
user158335

7
내 시스템에 적어도 notify-sendPATHcron 작업에 대한도. 아래 답변을 참조하십시오 .
krlmlr

2
우분투 17.04의 솔루션이 아닙니다. 대신 askubuntu.com/a/472769/413683askubuntu.com/a/834479/413683을 참조하십시오 .
Mateusz Piotrowski

2
이것은 문제가 아닙니다. 문제는 cron 스크립트가 사용자 세션에서 실행되지 않으며 사용자 로그인 세션 환경에 대한 개념이 없다는 것입니다. 알림을 보내려면 알림을 보내려면 dbus 세션 버스에 연결해야하므로, 올바른 세션 버스에 연결되지 않은 경우 바이너리가 호출되는 경로는 중요하지 않습니다.
dobey

2
이것은 답이 아닙니다. 실행 파일을 찾을 수 없으면 실행되지 않지만 BUT : 1. notify-send가 PATH에 있으므로 찾을 수 있습니다. 2. PATH에 없었더라도 여전히 전체 경로를 지정합니다. 실제로 DBUS_SESSION_BUS_ADDRESS를 알림 전송에 설정해야하므로 작동하지 않습니다. 정답은 kmir입니다.
크리스 제이스

31

적어도 Gnome Shell에서는 13.04의 상황이 다르게 보입니다.

먼저, 이것은 루트가 아닌 env사용자 zzyxy의 cron 작업 에서 실행될 때 인쇄되는 것입니다.

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

notify-send작동 하려면 ubuntuforums.org에 대한 DahitiF의 의견 에 따라 DBUS_SESSION_BUS_ADDRESS환경 변수 를 설정해야 합니다 . 실제 작업 설명에 다음을 추가하십시오.

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

설정이 필요하지 않은 것 같습니다 DISPLAY.


4
고마워, 이것이 마침내 나를 위해 일한 것입니다. Xubuntu에서는로 변경 gnome-session해야 xfce4-session합니다.
shrx

이것은 14.04에서 작동 할 수있는 유일한 대답이며 받아 들인 것의 명백한 힌트입니다.
Wtower

1
나는 없었고 대신 gnome-session사용 gnome-shell했다 (또한 2 pids를 얻을 수 gnome-shell-calendar-server있으므로 주의하십시오 pgrep). 또한 DISPLAY=:02 개의 화면을 사용하고 있으며 정의되지 않았기 때문에 필요 했습니다. 감사!
soyuka

(++ CB에 같은) 당신이 스왑을 OPENBOX를 사용하는 경우 openboxgnome-session.
ACK_stoverflow

이것은 정답이며, 받아 들여진 정답조차 정확하지 않으며, 필요하지 않은 DISPLAY 변수에 대해 이야기하거나 실제로 문제를 해결합니다.
크리스 제이스

24

notify-sendcron으로 시작할 때 명령 이 화면에 메시지를 표시하지 않습니다. 스크립트 상단에 대상 디스플레이를 추가하면됩니다 (예 :

export DISPLAY=:0

이것은 14.10에서해야했던 일입니다. 그렇지 않으면이 오류가 발생합니다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
이. 그리고 echo $DISPLAY터미널을 사용하여 디스플레이가 실제로 있는지 확인하십시오 :0(일반적으로 항상 그런 것은 아닙니다).
Mark

이것 만이 나를 위해 일했습니다. 저는 Linux Mint를 사용하고 있습니다
Harendra Singh

5

우분투 14.04 의 경우 위의 klrmr의 답변 이 정답입니다. 통지를 보내기 위해 $ DISPLAY에서 DISPLAY를 설정하거나 전체 경로를 명확하게 표현할 필요는 없습니다.

다음은 랩탑의 배터리 상태가 너무 낮아질 때 가상 머신을 종료하는 데 사용하는 크론 스크립트입니다. klrmr의 응답에서 DBUS_SESSION_BUS_ADDRESS 행 설정은 최종적으로 경고가 올바르게 작동하도록 수정 한 것입니다.

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

이것은 나에게도 완벽하게 작동하는 솔루션이었습니다. crontab에서 실행하는 스크립트에 "eval ..."행을 추가했습니다. 이제는 완벽하게 작동합니다.
Mtl Dev

2

우분투 16.04의 경우 명시 적 경로가 필요합니다. 추가하는 문제를 해결했습니다.

디스플레이 = : 0

호출 통지 보내기 전에 crontab의 첫 줄에.


이것이 16.04에서 작동하는 데 필요한 유일한 것입니다.
Jonathan Landrum

1

첫 번째 범인은 crontab 파일이며 스크립트를 실행할 사용자 이름을 언급해야하며 루트로 유지하는 것이 좋습니다.

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

그런 다음 스크립트 내에서 GUI 사용자의 user_name을 사용하고 GUI를 소유 한 사용자로 명령을 실행하기 위해 "sudo 또는 su"로 통지를 보내도록해야합니다.

예 :

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

또는

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

여기서 gnome_user_name로그인 당신 인 GUI 세션을 시작한 사용자의 사용자 이름이며, 당신이 그것을 동적 픽업을하려는 경우, 당신은 그것을 얻을 수

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

예 :

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

또는

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

1
사용자 이름이 X 자보다 길면 사용자 이름이 잘립니다. 예를 들어, 내 사용자 이름은 oniltonmaciel이지만 $GNOME_USER표시 onilton+되지 않습니다 (작동하지 않음)
Onilton Maciel

더 나은 명령으로 수정
S471

1

바이너리가 dbus 주소를 검색하는 방식이 최근에 변경된 것 같습니다. "notify-send 0.7.6"을 사용하는 Ubuntu 15.04 (Vivid Vervet)에서는 다음 두 변수가 필요합니다.

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

'krlmlr'의 문장은 정밀하게 평가되고 올바른 주소를 설정하지만 대화 상자는 크론 작업에서 나타나지 않습니다.


0

crontab의 스크립트가 루트로 실행중인 경우 위의 답변이 작동하지 않을 수 있습니다. 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 
}

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


0

dbus-session프로세스 에 의존하는 것이 더 좋으면 DBUS_SESSION_BUS_ADDRESS존재하는 모든 시스템에서 실행 중이어야합니다 .

스크립트를 작성하십시오.

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

실행 가능하게 만드십시오.

$ chmod +x ~/notify.sh

crontab에 추가하십시오.

* * * * * $HOME/notify.sh

0

이것은 우분투 15.10에서 작업하는 데 영원히 걸렸습니다. 사용자에게 정상적인 환경을 제공하는 소스를 추가해야했습니다. 내 디스플레이는 어떤 이유로 든 : 1이었습니다. gnome-session을 먼저 사용하면 DBUS_SESSION_BUS_ADDRESS 조회에 대해 pid가 발생합니다.

# 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

방금 우분투 15.10의 계피 데스크탑에서 다음 레시피를 사용하여 작동하도록했습니다.

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"

요령은 'cinnamon-session'이 pgrep가 찾기에는 너무 길다는 것을 깨달았습니다.

$ 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

내 grep이 에일리어싱되기 때문에 \ grep도 사용해야했습니다.

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

0

우분투 18.04에서 i3을 사용합니다. 이 문제를 해결하는 방법은 다음과 같습니다.

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


0

로케일 python3로 crontab에서 호출 하여 발생한 문제 UTF-8.

TL; DR : 로케일이있는 crontab의 접두사 호출 :

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

click 및 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

libnotify를 사용하는 모든 crontab 스크립트에는 다음을 사용합니다.

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

notify_user # and do other stuff

루트 모드에서 cron을 사용하더라도 작동합니다.


0

X_user와 X_userid 만 있으면됩니다. 아래의 명령으로 두 가지를 모두 교체하십시오.

체계적인 솔루션

/etc/systemd/system/opreminder.service # 서비스 파일

[Unit]
Descrption=some service to run

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


/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 # 스크립트

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

서비스 파일이 원하는 사용자로 이미 설정된 경우 sudo -u를 사용할 필요가 없습니다.

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.