แสดงการแจ้งเตือนในการแสดง X ทั้งหมดที่ทำงานอยู่


16

ใช้บรรทัดคำสั่งฉันต้องการแสดงการแจ้งเตือนบนจอแสดงผล X ที่ทำงานทุกครั้ง (และเรียกใช้คอนโซล)

สิ่งที่ต้องการ:

notify-send-all 'Warning' 'Nuclear launch in 5 minutes, please evacuate'

มีโปรแกรมที่จะทำเช่นนี้หรือไม่? ถ้าไม่สามารถใช้กับ bash ได้หรือไม่


1
สำหรับผู้ที่มาที่นี่ในปีต่อ ๆ มามีฟังก์ชั่น inform_all อย่างง่ายในคำตอบนี้ซึ่งทำงานใน Ubuntu 16.04 และสามารถใช้ในสคริปต์ที่รูทโดยรูท
mivk

คำตอบ:


16

คุณสามารถส่งข้อความไปยังคอนโซลทั้งหมดด้วยกำแพงคำสั่ง

สำหรับการส่งการแจ้งเตือนภายใต้ X จะมีการแจ้งเตือนส่งซึ่งจะส่งการแจ้งเตือนไปยังผู้ใช้ปัจจุบันบนจอแสดงผลปัจจุบัน (จากคำถามของคุณฉันเดาว่าคุณรู้เรื่องนี้อยู่แล้ว) คุณสามารถสร้างมันขึ้นมาได้ด้วยการเขียนสคริปต์ทุบตี โดยทั่วไปคุณต้องค้นหาว่าผู้ใช้รายใดที่ X-Display เมื่อคุณได้รับข้อมูลนี้คุณสามารถใช้การแจ้งเตือน - ส่งเช่นนี้:

DISPLAY=:0 sudo -u fschmitt notify-send "Message"

โดยที่ fschmitt เป็นผู้ใช้ที่แสดง 0 คุณสามารถแยกเอาต์พุตของคำสั่ง "who" เพื่อค้นหาผู้ใช้และจอแสดงผลทั้งหมด ผลลัพธ์มีลักษณะเช่นนี้

[edinburgh:~]$ who
markmerk3 tty7         2010-09-23 10:59 (:0)
markmerk3 pts/1        2010-09-30 13:30 (:0.0)
fschmitt pts/2        2010-10-08 11:44 (ip-77-25-137-234.web.vodafone.de)
markmerk3 pts/0        2010-09-29 18:51 (:0.0)
seamonkey pts/6        2010-09-27 15:50 (:1.0)
markmerk3 pts/5        2010-09-27 14:04 (:0.0)
seamonkey tty8         2010-09-27 15:49 (:1)
markmerk3 pts/13       2010-09-28 17:23 (:0.0)
markmerk3 pts/3        2010-10-05 10:40 (:0.0)

คุณเห็นมีผู้ใช้สองคนที่ใช้งานเซสชัน X, markmerk3 ที่จอแสดงผล 0 และ seamonkey ที่จอแสดงผล 1 ฉันคิดว่าคุณต้อง grep สำหรับ tty [0-9] * จากนั้นมั่นใจได้ว่าในตอนท้ายของบรรทัดที่มี (: [0 -9.] *) เพื่อกำจัดการเข้าสู่ระบบคอนโซลและแยก id ที่แสดงออกจากสตริงระหว่างวงเล็บ


2
คำสั่งwhoจะบอกคุณว่าใครเข้าสู่ระบบและที่ X แสดงการเข้าสู่ระบบที่เป็น คุณอาจต้องกรองมันบ้าง
tante

1
who | awk '/\(:[0-9]+\)/ {gsub("[:|(|)]","");print "DISPLAY=:"$5 " sudo -u " $1 " notify-send \"Message\""}' | bashในขณะที่มันอาจจะดีกว่าที่จะใช้เพียงห่วงในเชลล์สคริปต์คุณก็สามารถทำสิ่งที่ชอบ นอกจากนี้คุณอาจต้องการดูunix.stackexchange.com/questions/1596/…
Steven D

8

เธรดนี้ค่อนข้างเก่าขออภัย แต่ฉันหวังว่าฉันยังสามารถเพิ่มสิ่งที่มีประโยชน์ให้กับหัวข้อ (เช่น Josef Kufner เขียนสคริปต์ที่ดีมันแค่ยาวเกินไปสำหรับรสนิยมของฉันและใช้ PHP)

ฉันต้องการเครื่องมือตามที่อธิบายไว้ในคำถามเดิม (เพื่อส่งข้อความถึงผู้ใช้ X-active ทั้งหมด) และจากคำตอบที่นี่ฉันเขียนสคริปต์ bash-only ตัวนี้ซึ่งค้นหาผู้ใช้ X-active (โดยใช้ 'who') จากนั้นเรียกใช้การแจ้งเตือน - ส่งสำหรับผู้ใช้ที่ใช้งานอยู่ทุกคน

และที่ดีที่สุด: คุณสามารถใช้สคริปต์ของฉันเหมือนกับ "แจ้งเตือน - ส่ง" พร้อมพารามิเตอร์ทั้งหมด! ;-)

แจ้งส่งทั้งหมด:

#!/bin/bash
PATH=/usr/bin:/bin

XUSERS=($(who|grep -E "\(:[0-9](\.[0-9])*\)"|awk '{print $1$5}'|sort -u))
for XUSER in $XUSERS; do
    NAME=(${XUSER/(/ })
    DISPLAY=${NAME[1]/)/}
    DBUS_ADDRESS=unix:path=/run/user/$(id -u ${NAME[0]})/bus
    sudo -u ${NAME[0]} DISPLAY=${DISPLAY} \
                       DBUS_SESSION_BUS_ADDRESS=${DBUS_ADDRESS} \
                       PATH=${PATH} \
                       notify-send "$@"
done

คัดลอกโค้ดด้านบนลงในไฟล์ชื่อ "alert-send-all" ทำให้สามารถเรียกใช้งานได้และคัดลอกไปยัง/ usr / local / binหรือ/ usr / bin (ตามที่คุณต้องการ) จากนั้นเรียกใช้เช่นเป็น root ในคอนโซลเซสชันดังนี้:

notify-send-all -t 10000 "Warning" "The hovercraft is full of eels!"

ฉันใช้มันหลายเดือนแล้วบนเครื่องต่าง ๆ และไม่มีปัญหาใด ๆ และฉันได้ทดสอบกับเดสก์ท็อป MATE และ Cinnamon ยังประสบความสำเร็จในการรันภายใน cron และ anacron

ฉันเขียนสคริปต์นี้สำหรับ / ภายใต้ ArchLinux ดังนั้นโปรดบอกฉันว่าคุณกำลังมีปัญหากับการกระจาย Linux หรือเดสก์ท็อปอื่น


|egrep?? egrep คำสั่งคืออะไร?
Sw0ut

@ Sw0ut เช่น egrep เป็นคำสั่งแน่นอน แต่ในหน้า man ของ grep (1) บอกว่า egrep, fgrep และ rgrep นั้นเลิกใช้แล้วและใช้รูปแบบที่เทียบเท่าของพวกเขา "grep -E", "grep -F" และ "grep -r"
rsuarez

แทนที่จะawk '{print $1$5}'เป็นการดีกว่าที่จะใช้awk '{print $1$NF}'เพื่อไม่ให้เกิดความเสียหายในบางภาษาที่มีการจัดรูปแบบวันที่ด้วยช่องว่าง (เช่นJun 3แทน2017-06-03) นี่เป็นรุ่นสำหรับแจ้งผู้ใช้เฉพาะแทนผู้ใช้ทั้งหมด: gist.github.com/shvchk/ba2f0da49bf2f571d6bf606d96f289d7
Shevchuk

1
ทำงานได้อย่างยอดเยี่ยมบน Ubuntu หลังจากใช้งานgrep -Eและเพิ่ม/binลงในพา ธ (ดูการแก้ไข) อย่าลังเลที่จะยกเลิกหากคุณคัดค้าน
serv-inc

3

ฉันต้องการสิ่งนี้เช่นกันสำหรับการแจ้งเตือนทั่วทั้งระบบ นี่คือทางออกของฉัน มันสแกน / proc เพื่อค้นหาบัสเซสชั่นทั้งหมดจากนั้นจะดำเนินการแจ้งเตือนการส่งในแต่ละมัน (หนึ่งครั้งต่อบัส) ข้อโต้แย้งทั้งหมดจะถูกส่งผ่านไปยังการแจ้งเตือนการส่ง

#!/bin/bash

/bin/grep -sozZe '^DBUS_SESSION_BUS_ADDRESS=[a-zA-Z0-9:=,/-]*$' /proc/*/environ \
| /usr/bin/php -r '
        $busses = array();
        array_shift($argv);
        while($ln = fgets(STDIN)) {
                list($f, $env) = explode("\0", $ln, 2);
                if (file_exists($f)) {
                        $user = fileowner($f);
                        $busses[$user][trim($env)] = true;
                }
        }
        foreach ($busses as $user => $user_busses) {
                foreach ($user_busses as $env => $true) {
                        if (pcntl_fork()) {
                                posix_seteuid($user);
                                $env_array = array("DBUS_SESSION_BUS_ADDRESS" => preg_replace("/^DBUS_SESSION_BUS_ADDRESS=/", "", $env));
                                pcntl_exec("/usr/bin/notify-send", $argv, $env_array);
                        }
                }
        }
' -- "$@"

1

ใน Ubuntu 16.04 ฉันต้องการการแจ้งเตือนจากสคริปต์ที่ทำงานเป็น root จาก crontab หลังจากตั้งค่าตัวแปรสภาพแวดล้อมsudo -u $userไม่ทำงานด้วยเหตุผลบางอย่าง แต่sh -c "..." $userทำงานได้

ดังนั้นตอนนี้ฉันใช้ฟังก์ชั่นนี้:

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 
}

วิธีค้นหาตัวแปร DBUS_SESSION_BUS_ADDRESS อาจขึ้นอยู่กับการกระจายของคุณ ใน Ubuntu 16.04 มันอยู่ใน/run/user/$UID/dbus-sessionนั้นซึ่งสามารถหาได้ง่าย ถูกนำมาใช้ในการทำงานดังกล่าวข้างต้นจะได้รับการโพสต์จากชื่อผู้ที่ส่งกลับโดยid -uwho


วิธีการใช้งาน คุณสามารถช่วยฉันได้ไหม?
elgolondrino

0

นี่คือการอัปเดตสคริปต์ของ Andy: วิธีที่มันระบุว่าใช้DBUS_SESSION_BUS_ADDRESSไม่ได้กับ Centos 7 นอกจากนี้whoคำสั่งไม่ได้แสดงรายการบางเซสชันด้วยเหตุผลบางอย่างดังนั้นฉันจึงแยกวิเคราะห์ps auxผลลัพธ์แทน สคริปต์นี้ถือว่าผู้ใช้เข้าสู่ระบบโดยใช้ X2GO ( nxagent) แต่ควรปรับให้เข้ากับกรณีอื่นได้ง่าย

#!/bin/bash
PATH=/usr/bin:/bin
NOTIFY_ARGS='-u critical "Shutdown notice" "THE SYSTEM IS GOING DOWN TODAY AT 23:00.\nWe recommend you to save your work in time\!" -i /usr/share/icons/Adwaita/32x32/devices/computer.png -t 28800000'

function extract_displays {
    local processes=$1
    processes=$(printf '%s\n' "$processes" | grep -P "nxagent.+:\d+")
    ids=$(printf '%s\n' "$processes" | grep -oP "\W\K:(\d)+")
    echo $ids
}


function find_dbus_address {
    local name=$1
    PID=$(pgrep 'mate-session' -u $name)
    if [ -z "$PID" ]; then
        PID=$(pgrep 'gnome-session' -u $name)
    fi
    if [ -z "$PID" ]; then
        PID=$(pgrep 'xfce4-session' -u $name)
    fi

    exp=$(cat /proc/$PID/environ | grep -z "^DBUS_SESSION_BUS_ADDRESS=")
    echo $exp
}

PROCESSES=$(ps aux)
DISPLAY_IDS=$(extract_displays "$PROCESSES")
echo "Found the following DISPLAYS: $DISPLAY_IDS"
for DISPLAY in $DISPLAY_IDS; do
    NAME=$(printf '%s\n' "$PROCESSES" | grep -P "nxagent.+$DISPLAY" | cut -f1 -d ' ')
    DBUS_ADDRESS=$(find_dbus_address $NAME)
    echo "Sending message to NAME=$NAME DISPLAY=$DISPLAY DBUS_ADDRESS=$DBUS_ADDRESS"
    echo "NOTIFY_ARGS=$NOTIFY_ARGS"
    eval sudo -u ${NAME} DISPLAY=${DISPLAY} ${DBUS_ADDRESS} PATH=${PATH} notify-send $NOTIFY_ARGS
done

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.