Hiển thị thông báo trên tất cả các màn hình X đang chạy


16

Sử dụng dòng lệnh, tôi muốn hiển thị thông báo trên mỗi màn hình X đang chạy. (và bảng điều khiển đang chạy)

Cái gì đó như:

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

Có một chương trình sẽ làm điều này? Nếu không, điều này có thể được thực hiện với bash?


1
Đối với những người đến đây nhiều năm sau, có một hàm notify_all đơn giản trong câu trả lời này hoạt động trong Ubuntu 16.04 và có thể được sử dụng trong các tập lệnh bắt đầu bằng root.
mivk

Câu trả lời:


16

Bạn có thể gửi tin nhắn đến tất cả các bảng điều khiển với tường lệnh.

Để gửi thông báo dưới X, có thông báo-gửi sẽ gửi thông báo cho người dùng hiện tại trên màn hình hiện tại. (Từ câu hỏi của bạn, tôi đoán bạn đã biết câu hỏi này.) Bạn có thể xây dựng dựa trên điều này với một số kịch bản bash. Về cơ bản, bạn phải tìm ra người dùng nào đang sử dụng X-Display. Khi bạn đã nhận được thông tin này, bạn có thể sử dụng thông báo gửi như thế này:

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

Trong đó fschmitt là người dùng ở màn hình 0. Bạn có thể phân tích đầu ra của lệnh "who" để tìm tất cả người dùng và màn hình của họ. Đầu ra trông như thế này

[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)

Bạn thấy đấy, có hai người dùng đang chạy phiên X, markmerk3 ở màn hình 0 và seamonkey ở màn hình 1. Tôi nghĩ bạn cần grep cho tty [0-9] * sau đó đảm bảo rằng ở cuối dòng có (: [0 -9.] *) Để thoát khỏi đăng nhập bảng điều khiển và trích xuất id hiển thị từ chuỗi giữa các dấu ngoặc đơn.


2
Lệnh whocho bạn biết ai đã đăng nhập và trên đó X hiển thị thông tin đăng nhập đó. Bạn có thể phải lọc nó một chút.
tante

1
Mặc dù có thể tốt hơn nếu chỉ sử dụng một vòng lặp trong tập lệnh shell, bạn luôn có thể làm điều gì đó như thế who | awk '/\(:[0-9]+\)/ {gsub("[:|(|)]","");print "DISPLAY=:"$5 " sudo -u " $1 " notify-send \"Message\""}' | bash. Ngoài ra, bạn có thể muốn xem unix.stackexchange.com/questions/1596/NH
Steven D

8

Chủ đề này hơi cũ, xin lỗi, nhưng tôi hy vọng tôi vẫn có thể thêm một cái gì đó hữu ích cho chủ đề. (cũng là Josef Kufner đã viết một kịch bản hay, nó chỉ hơi dài một chút so với sở thích của tôi và nó sử dụng PHP)

Tôi cũng cần một công cụ như được mô tả trong câu hỏi ban đầu (để gửi tin nhắn cho tất cả người dùng X đang hoạt động). Và dựa trên các câu trả lời ở đây, tôi đã viết tập lệnh bash nhỏ này, tìm kiếm người dùng X hoạt động (sử dụng 'ai'), sau đó chạy thông báo gửi cho mọi người dùng đang hoạt động.

Và tốt nhất: bạn có thể sử dụng tập lệnh của tôi chính xác như "thông báo gửi", với tất cả các tham số của nó! ;-)

thông báo-gửi-tất cả:

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

Sao chép mã ở trên vào một tệp có tên "notify-send-all", làm cho nó có thể thực thi được và sao chép nó vào / usr / local / bin hoặc / usr / bin (như bạn muốn). Sau đó chạy nó, ví dụ như root trong phiên giao diện điều khiển như thế này:

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

Tôi đang sử dụng nó vài tháng nay, trên các máy khác nhau và cho đến nay không có vấn đề gì và tôi đã thử nghiệm nó với máy tính để bàn MATE và Cinnamon. Cũng chạy thành công nó trong cron và anacron.

Tôi đã viết tập lệnh này cho / dưới ArchLinux, vì vậy vui lòng cho tôi biết nếu bạn gặp sự cố trên các bản phân phối hoặc máy tính để bàn khác của Linux.


|egrep?? egrep là một lệnh?
Sw0ut

@ Sw0ut, egrep thực sự là một lệnh. Nhưng trong trang man của grep (1) nói rằng egrep, fgrep và rgrep không được dùng nữa, và nên sử dụng các dạng tương đương "grep -E", "grep -F" và "grep -r".
rsuarez

Thay vào đó awk '{print $1$5}', tốt hơn là sử dụng awk '{print $1$NF}', để nó không bị hỏng ở một số địa điểm nơi ngày được định dạng bằng dấu cách (ví dụ Jun 3thay vì 2017-06-03). Đây cũng là phiên bản để thông báo cho người dùng cụ thể thay vì tất cả người dùng: gist.github.com/shvchk/ba2f0da49bf2f571d6bf606d96f289d7
Shevchuk

1
Hoạt động tuyệt vời trên Ubuntu sau khi sử dụng grep -Evà thêm /binvào đường dẫn (xem phần chỉnh sửa). Vui lòng hoàn nguyên nếu bạn phản đối
serv-inc

3

Tôi cũng cần điều này cho một số thông báo trên toàn hệ thống. Đây là giải pháp của tôi. Nó quét / Proc để tìm tất cả các bus phiên và sau đó nó thực thi gửi thông báo trên mỗi cái (một lần trên mỗi xe buýt). Tất cả các đối số được chuyển không thay đổi để gửi thông báo thực sự.

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

Trong Ubuntu 16.04, tôi muốn thông báo từ tập lệnh chạy bằng root từ crontab. Sau khi thiết lập các biến môi trường, sudo -u $userkhông hoạt động vì một số lý do, nhưng sh -c "..." $userkhông hoạt động.

Vì vậy, bây giờ tôi sử dụng chức năng này:

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 
}

Cách tìm biến DBUS_SESSION_BUS_ADDRESS có thể phụ thuộc vào phân phối của bạn. Trong Ubuntu 16.04, nó nằm trong /run/user/$UID/dbus-session, có thể đơn giản là có nguồn gốc. id -uđược sử dụng trong chức năng trên để lấy UID từ tên người dùng được trả về bởi who.


Làm thế nào để sử dụng nó? Bạn có thể giúp tôi được không?
elgolondrino

0

Đây là bản cập nhật tập lệnh của Andy: Cách nó xác định DBUS_SESSION_BUS_ADDRESSkhông hoạt động trên Centos 7. Ngoài ra, wholệnh không liệt kê một số phiên vì một số lý do, vì vậy tôi ps auxthay vào đó phân tích đầu ra. Kịch bản này giả định rằng người dùng đã đăng nhập bằng X2GO ( nxagent), nhưng nó sẽ đơn giản để điều chỉnh cho các trường hợp khác.

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

-1
users=$(who | awk '{print $1}')

for user in $users<br>
do
        DISPLAY=:0 sudo -u $user notify-send "hello!!"
done
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.