Pokaż powiadomienie na wszystkich uruchomionych wyświetlaczach X.

16

Korzystając z wiersza poleceń, chcę wyświetlać powiadomienie na każdym uruchomionym ekranie X. (i uruchomiona konsola)

Coś jak:

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

Czy istnieje program, który to zrobi? Jeśli nie, czy można to zaimplementować za pomocą bash?

Stefan
źródło
1
Dla osób, które przyjadą tu po latach, w tej odpowiedzi dostępna jest prosta funkcja powiadomienie_wszystkie, która działa w Ubuntu 16.04 i może być używana w skryptach uruchamianych przez root.
mivk

Odpowiedzi:

16

Możesz wysłać wiadomość do wszystkich konsol za pomocą ściany poleceń.

Do wysyłania powiadomień zgodnie z X-em wysyłane jest powiadomienie wysyłające powiadomienie do bieżącego użytkownika na bieżącym ekranie. (Wydaje mi się, że z tego pytania już to znasz.) Możesz na tym oprzeć się za pomocą skryptów bash. Zasadniczo musisz dowiedzieć się, którzy użytkownicy korzystają z X-Displays. Po otrzymaniu tych informacji możesz użyć powiadomienia-wysyłania w następujący sposób:

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

Gdzie fschmitt jest użytkownikiem na wyświetlaczu 0. Możesz przeanalizować dane wyjściowe polecenia „who”, aby znaleźć wszystkich użytkowników i ich ekrany. Dane wyjściowe wyglądają tak

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

Widzisz, jest dwóch użytkowników uruchamiających sesje X, markmerk3 na wyświetlaczu 0 i seamonkey na wyświetlaczu 1. Myślę, że musisz grep dla tty [0-9] *, a następnie upewnij się, że na końcu wiersza jest (: [0 -9.] *), Aby pozbyć się logowania do konsoli i wyodrębnić identyfikator wyświetlania z ciągu między nawiasami.

fschmitt
źródło
2
Polecenie whoinformuje, kto jest zalogowany i na którym X wyświetla się to logowanie. Być może będziesz musiał go nieco odfiltrować.
tante
1
Chociaż prawdopodobnie lepiej jest po prostu użyć pętli w skrypcie powłoki, zawsze możesz zrobić coś takiego who | awk '/\(:[0-9]+\)/ {gsub("[:|(|)]","");print "DISPLAY=:"$5 " sudo -u " $1 " notify-send \"Message\""}' | bash. Ponadto możesz zobaczyć unix.stackexchange.com/questions/1596/…
Steven D
8

Ten wątek jest nieco stary, przepraszam, ale mam nadzieję, że nadal mogę dodać coś użytecznego do tematu. (także Josef Kufner napisał fajny skrypt, na mój gust był trochę za długi i używa PHP)

Potrzebowałem także narzędzia opisanego w pierwotnym pytaniu (aby wysłać wiadomość do wszystkich aktywnych użytkowników X). I na podstawie odpowiedzi tutaj napisałem ten mały skrypt typu bash, który wyszukuje aktywnych użytkowników X (używając „kto”), a następnie uruchamia powiadomienie-wysyłanie dla każdego aktywnego użytkownika.

A najlepsze: możesz użyć mojego skryptu dokładnie tak jak „powiadom-wyślij” ze wszystkimi jego parametrami! ;-)

powiadom-wyślij-wszystko:

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

Skopiuj powyższy kod do pliku o nazwie „powiadom-wyślij-wszystko”, spraw, aby był wykonywalny i skopiuj go do / usr / local / bin lub / usr / bin (jak chcesz). Następnie uruchom go np. Jako root w sesji konsoli jak poniżej:

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

Używam go już od kilku miesięcy na różnych maszynach i jak dotąd nie miałem żadnych problemów, i przetestowałem go na komputerach stacjonarnych MATE i Cinnamon. Z powodzeniem działa również w cron i anacron.

Napisałem ten skrypt dla / pod ArchLinux, więc proszę powiedz mi, jeśli masz problemy z innymi dystrybucjami Linuksa lub komputerami stacjonarnymi.

Andy
źródło
|egrep?? czy egrep jest poleceniem?
Sw0ut
@ Sw0ut, egrep jest rzeczywiście poleceniem. Ale na stronie man grep (1) mówi, że egrep, fgrep i rgrep są przestarzałe i zaleca się stosowanie ich równoważnych form „grep -E”, „grep -F” i „grep -r”.
rsuarez
Zamiast awk '{print $1$5}'tego lepiej jest używać awk '{print $1$NF}', aby nie pękało w niektórych lokalizacjach, w których data jest formatowana spacjami (np. Jun 3Zamiast 2017-06-03). Oto również wersja powiadamiająca określonego użytkownika zamiast wszystkich użytkowników: gist.github.com/shvchk/ba2f0da49bf2f571d6bf606d96f289d7
Shevchuk
1
Działa znakomicie na Ubuntu po użyciu grep -Ei dodaniu /bindo ścieżki (patrz edycja). Możesz się wycofać, jeśli sprzeciwisz się
serv-inc
3

Potrzebowałem tego również w przypadku niektórych powiadomień systemowych. Oto moje rozwiązanie. Skanuje / proc, aby znaleźć wszystkie magistrale sesji, a następnie wykonuje powiadomienie-wysyłanie na każdym z nich (raz na magistralę). Wszystkie argumenty są przekazywane niezmienione do rzeczywistego powiadomienia-wysłania.

#!/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);
                        }
                }
        }
' -- "$@"
Josef Kufner
źródło
1

W Ubuntu 16.04 chciałem otrzymywać powiadomienia ze skryptu działającego jako root z crontab. Po ustawieniu zmiennych środowiskowych sudo -u $usernie działał z jakiegoś powodu, ale sh -c "..." $userdziała.

Używam teraz tej funkcji:

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 
}

Jak znaleźć zmienną DBUS_SESSION_BUS_ADDRESS, prawdopodobnie zależy od twojej dystrybucji. W Ubuntu 16.04 jest on dostępny /run/user/$UID/dbus-sessioni można go po prostu zdobyć. id -ujest używany w funkcji powyżej, aby uzyskać identyfikator UID z nazwy użytkownika zwróconej przez who.

mivk
źródło
Jak tego użyć? Możesz mi pomóc?
elgolondrino
0

Oto aktualizacja skryptu Andy'ego: Sposób, w jaki to określił DBUS_SESSION_BUS_ADDRESS, nie działa na Centos 7. Również whopolecenie z jakiegoś powodu nie wyświetlało niektórych sesji, więc analizuję dane ps auxwyjściowe. Ten skrypt zakłada, że ​​użytkownicy są zalogowani za pomocą X2GO ( nxagent), ale powinno być łatwe do dostosowania w innych przypadkach.

#!/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
jpf
źródło
-1
users=$(who | awk '{print $1}')

for user in $users<br>
do
        DISPLAY=:0 sudo -u $user notify-send "hello!!"
done
Vicent
źródło