แจ้งเตือนการส่งไม่ทำงานจาก crontab


44

ฉันสร้างสคริปต์ที่ควรแจ้งให้ฉันทราบเมื่อมีมังงะบทใหม่ที่ฉันกำลังอ่าน ฉันใช้คำสั่ง alert-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-alert จะสามารถหาวิธีแสดงข้อความได้ แต่คุณควรพิจารณาส่งข้อมูลไปที่ 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
นั่นรวมถึงแมว, wget, ถ้า, ปล่อย, grep, echo, หรือไม่?
user158335

7
อย่างน้อยในระบบของฉันnotify-sendอยู่ในช่วงPATHที่งาน cron ดูคำตอบของฉันด้านล่าง
krlmlr

2
มันไม่ใช่ทางออกสำหรับ Ubuntu 17.04 ดูaskubuntu.com/a/472769/413683และaskubuntu.com/a/834479/413683แทน
Mateusz Piotrowski

2
นี่ไม่ใช่ปัญหา ปัญหาคือสคริปต์ cron ไม่ทำงานภายใต้เซสชันผู้ใช้และไม่มีแนวคิดเกี่ยวกับสภาพแวดล้อมของเซสชันการเข้าสู่ระบบของผู้ใช้ เนื่องจากการแจ้งเตือนการส่งจำเป็นต้องเชื่อมต่อกับบัสเซสชัน dbus เพื่อส่งการแจ้งเตือนมันจะไม่สำคัญว่าเส้นทางใดที่จะเรียกไบนารีจากเมื่อไม่เชื่อมต่อกับบัสเซสชันที่ถูกต้อง
dobey

2
นี่ไม่ใช่คำตอบ แน่นอนว่าถ้าไม่สามารถหาตำแหน่งที่ปฏิบัติการได้มันจะไม่ทำงาน แต่: 1. การแจ้งเตือน - ส่งอยู่บนเส้นทางดังนั้นมันจะอยู่ 2. แม้ว่าจะไม่ได้อยู่ในเส้นทางและคุณระบุเส้นทางแบบเต็มก็ยังจะ ไม่ทำงานเพราะจริง ๆ แล้วต้องตั้งค่า DBUS_SESSION_BUS_ADDRESS สำหรับส่ง - แจ้งเตือน และคำตอบที่ถูกต้องคือจาก kmir
Kris Jace

31

ทุกอย่างดูเหมือนจะแตกต่างกันไปใน 13.04 อย่างน้อยก็ใน Gnome Shell

สิ่งแรกคือสิ่งที่envพิมพ์เมื่อเรียกใช้จากzzyxyงาน cron ของผู้ใช้(ไม่ใช่ของ root):

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ให้สามารถใช้งานได้ดูเหมือนว่าจำเป็นต้องตั้งค่าDBUS_SESSION_BUS_ADDRESSตัวแปรสภาพแวดล้อมตามความคิดเห็นของ DahitiF ที่ ubuntuforums.org เพียงเพิ่มรายละเอียดงานจริงของคุณต่อไปนี้:

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

DISPLAYมันไม่ได้ดูเหมือนจะมีความจำเป็นต้องตั้งค่า


4
ขอบคุณนี่คือสิ่งที่ใช้งานได้ในที่สุดสำหรับฉัน เมื่อวันที่ Xubuntu คุณจะมีการเปลี่ยนแปลงไปgnome-session xfce4-session
ยักไหล่

นี่เป็นคำตอบเดียวสำหรับการทำงาน 14.04 พร้อมด้วยคำใบ้ที่ชัดเจนของคำตอบที่ได้รับการยอมรับ
Wtower

1
ฉันไม่มีgnome-sessionและใช้gnome-shellแทน (ระวังgnome-shell-calendar-serverให้ดีpgrepจะได้ 2 pids) ฉันต้องการDISPLAY=:0เพราะฉันใช้หน้าจอ phisical 2 หน้าจอและไม่ได้กำหนดไว้ ขอบคุณ!
soyuka

หากคุณกำลังใช้ Openbox (เช่นเดียวกับ CB ++) ให้แลกเปลี่ยนสำหรับopenbox gnome-session
ACK_stoverflow

นี่คือคำตอบที่ถูกต้องและคำตอบที่ยอมรับนั้นไม่ถูกต้องมันพูดถึงตัวแปร DISPLAY ที่ไม่จำเป็นแม้แต่จะแก้ปัญหานั้นไม่ได้
Kris Jace

24

คำสั่งnotify-sendจะไม่แสดงข้อความบนหน้าจอของคุณเมื่อเริ่มต้นโดย cron เพียงเพิ่มการแสดงเป้าหมายที่ด้านบนสุดของสคริปต์ตัวอย่างเช่น

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(มักจะเป็น แต่ไม่เสมอไป)
ทำเครื่องหมาย

สิ่งนี้ใช้ได้กับฉันเท่านั้นฉันกำลังใช้ Linux Mint
Harendra Singh

5

อย่างน้อย Ubuntu 14.04 การตอบสนองของ klrmr ด้านบนเป็นคำตอบที่ถูกต้อง ไม่จำเป็นต้องตั้งค่า DISPLAY หรือเชื่อมต่อเส้นทางแบบเต็มสำหรับการแจ้งเตือนการส่งหรือสิ่งอื่นตามปกติใน $ PATH

ด้านล่างเป็นสคริปต์ cron ที่ฉันใช้เพื่อปิดเครื่องเสมือนเมื่อสถานะแบตเตอรี่ของแล็ปท็อปต่ำเกินไป การตั้งค่าบรรทัด DBUS_SESSION_BUS_ADDRESS ในการตอบสนองของ klrmr ด้านบนคือการปรับเปลี่ยนที่ทำให้คำเตือนทำงานได้อย่างถูกต้องในที่สุด

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

นี่เป็นวิธีการแก้ปัญหาที่ทำงานได้อย่างสมบูรณ์แบบสำหรับฉันเช่นกันฉันเพิ่งเพิ่มบรรทัด "eval ... " ในสคริปต์ของฉันที่ฉันเรียกใช้จาก crontab - ตอนนี้มันทำงานได้อย่างสมบูรณ์
Mtl Dev

2

ในกรณีของฉันกับ Ubuntu 16.04 จำเป็นต้องใช้พา ธ ที่ชัดเจนใด ๆ ฉันแก้ปัญหาที่เพิ่งเพิ่ม

DISPLAY =: 0

ที่บรรทัดแรกของ crontab ก่อนโทรแจ้งเตือน - ส่ง


นี่เป็นสิ่งเดียวที่จำเป็นในการทำให้มันทำงานบน 16.04
Jonathan Landrum

1

ผู้ร้ายคนแรกคือไฟล์ crontab ของคุณคุณต้องพูดถึงชื่อผู้ใช้ที่สคริปต์จะต้องถูกเรียกใช้งานควรเก็บไว้เป็น root

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

จากนั้นคุณควรใช้ชื่อผู้ใช้ของผู้ใช้ GUI ภายในสคริปต์และเสริมเพื่อแจ้งเตือนการส่งด้วย "sudo หรือ su" เพื่อรันคำสั่งในฐานะผู้ใช้ที่เป็นเจ้าของ GUI

ตัวอย่าง:

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 ตัวอักษร usernma ของคุณจะถูกตัดทอน: ตัวอย่างเช่นชื่อผู้ใช้ของฉันคือoniltonmacielแต่$GNOME_USERจะแสดงonilton+(ไม่ทำงาน)
Onilton Maciel

แก้ไขด้วยคำสั่งที่ดีกว่า
S471

1

วิธีที่ไบนารีดึงที่อยู่ dbus ดูเหมือนจะเปลี่ยนไปเมื่อเร็ว ๆ นี้ บน Ubuntu 15.04 (Vivid Vervet) ด้วย "แจ้งเตือน - ส่ง 0.7.6" จำเป็นต้องใช้ตัวแปรสองตัวต่อไปนี้:

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

คำสั่งโดย 'krlmlr' จะประเมินค่าที่ดีและตั้งค่าที่อยู่ที่ถูกต้อง แต่กล่องโต้ตอบจะไม่ปรากฏขึ้นจากงาน cron


0

หากสคริปต์ใน crontab ของคุณทำงานเป็น root คำตอบด้านบนอาจไม่ทำงาน ลองใช้ฟังก์ชันนี้ซึ่งใช้งานได้ดีกับฉันใน 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

สิ่งนี้ใช้เวลาตลอดไปในการทำงานบน Ubuntu 15.10 ต้องมีการเพิ่มแหล่งข้อมูลเพื่อให้ผู้ใช้งานได้รับ env ปกติ จอแสดงผลของฉันคือ: 1 ด้วยเหตุผลบางอย่างเช่นกัน การใช้ผลลัพธ์แรกของ gnome-session pid สำหรับการค้นหา 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

ฉันเพิ่งได้รับสิ่งนี้เพื่อทำงานกับเดสก์ทอปอบเชยบน Ubuntu 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"

เคล็ดลับคือการตระหนักว่า 'อบเชยเซสชั่น' ยาวเกินไปสำหรับ 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

ปัญหาที่เกิดจากการโทรpython3ใน crontab ด้วยUTF-8สถานที่เกิดเหตุ

TL; DR: การโทรคำนำหน้าใน crontab ด้วยโลแคลดังนี้:

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

ดูเพิ่มเติมคลิกและ 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

สำหรับสคริปต์ crontab ทั้งหมดที่ใช้ libnotify ฉันใช้สิ่งนี้:

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 แทนที่ทั้งสองในคำสั่งร้อง

วิธีแก้ปัญหาด้วย systemd

/etc/systemd/system/opreminder.service #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 #The สคริปต์

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