Eine Benachrichtigung über alle laufenden X-Displays anzeigen

16

Über die Befehlszeile möchte ich auf jeder laufenden X-Anzeige eine Benachrichtigung anzeigen. (und laufende Konsole)

Etwas wie:

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

Gibt es ein Programm, das dies erledigt? Wenn nicht, kann dies mit bash implementiert werden?

Stefan
quelle
1
Für Leute, die Jahre später hierher kommen, gibt es eine einfache notify_all-Funktion in dieser Antwort, die in Ubuntu 16.04 funktioniert und in Skripten verwendet werden kann, die von root gestartet wurden.
Mivk

Antworten:

16

Über die Befehlszeile können Sie eine Nachricht an alle Konsolen senden.

Für das Versenden von Benachrichtigungen unter X gibt es notify-send, das auf der aktuellen Anzeige eine Benachrichtigung an den aktuellen Benutzer sendet. (Aus Ihrer Frage geht hervor, dass Sie diese bereits kennen.) Darauf können Sie mit einigen Bash-Skripten aufbauen. Grundsätzlich muss man herausfinden, welche Benutzer sich auf welchen X-Displays befinden. Sobald Sie diese Informationen erhalten haben, können Sie notify-send wie folgt verwenden:

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

Wobei fschmitt der Benutzer bei Anzeige 0 ist. Sie können die Ausgabe des Befehls "who" analysieren, um alle Benutzer und ihre Anzeigen zu finden. Die Ausgabe sieht so aus

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

Sie sehen, es gibt zwei Benutzer, die X-Sitzungen ausführen, markmerk3 bei Anzeige 0 und seamonkey bei Anzeige 1. Ich denke, Sie müssen nach tty [0-9] * greifen und dann sicherstellen, dass am Ende der Zeile (: [0 -9.] *), Um die Konsolenanmeldungen zu entfernen und die Anzeige-ID aus der Zeichenfolge in Klammern zu extrahieren.

fschmitt
quelle
2
Der Befehl whoteilt Ihnen mit, wer angemeldet ist und auf welcher X-Anzeige sich diese Anmeldung befindet. Möglicherweise müssen Sie es etwas filtern.
Tante
1
Während es wahrscheinlich besser ist, nur eine Schleife in einem Shell-Skript zu verwenden, könnte man immer so etwas tun who | awk '/\(:[0-9]+\)/ {gsub("[:|(|)]","");print "DISPLAY=:"$5 " sudo -u " $1 " notify-send \"Message\""}' | bash. Vielleicht möchten Sie auch unix.stackexchange.com/questions/1596/…
Steven D
8

Dieser Thread ist ein bisschen alt, sorry, aber ich hoffe, dass ich dem Thema noch etwas Nützliches hinzufügen kann. (auch Josef Kufner hat ein schönes Skript geschrieben, es war für meinen Geschmack etwas zu lang und es benutzt PHP)

Ich brauchte auch ein Tool wie in der ursprünglichen Frage beschrieben (um eine Nachricht an alle aktiven X-Benutzer zu senden). Und basierend auf den Antworten hier habe ich dieses kleine Nur-Bash-Skript geschrieben, das nach aktiven X-Benutzern sucht (mit 'who') und dann notify-send für jeden aktiven Benutzer ausführt.

Und das Beste: Sie können mein Skript mit all seinen Parametern genauso verwenden wie "notify-send"! ;-)

benachrichtige-sende-alles:

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

Kopieren Sie den obigen Code in eine Datei mit dem Namen "notify-send-all", machen Sie ihn ausführbar und kopieren Sie ihn nach / usr / local / bin oder / usr / bin (wie Sie möchten). Dann starte es zB als root in einer Konsolensitzung wie folgt:

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

Ich benutze es jetzt mehrere Monate auf verschiedenen Computern und hatte bisher keine Probleme. Ich habe es mit MATE- und Cinnamon-Desktops getestet. Läuft auch erfolgreich in Cron und Anacron.

Ich habe dieses Skript für / unter ArchLinux geschrieben. Bitte teilen Sie mir mit, wenn Sie Probleme mit anderen Linux-Distributionen oder -Desktops haben.

Andy
quelle
|egrep?? ist egrep ein befehl?
Sw0ut
@Sw0ut, egrep ist ja ein befehl. In der Manpage von grep (1) heißt es jedoch, dass egrep, fgrep und rgrep veraltet sind und die Verwendung der entsprechenden Formen "grep -E", "grep -F" und "grep -r" empfohlen wird.
rsuarez
Stattdessen awk '{print $1$5}'ist es besser, es zu verwenden awk '{print $1$NF}', damit es bei einigen Gebietsschemata, bei denen das Datum mit Leerzeichen formatiert ist (z . B. Jun 3anstelle von 2017-06-03), nicht unterbrochen wird . Hier ist auch eine Version, um bestimmte Benutzer anstelle aller Benutzer zu benachrichtigen: gist.github.com/shvchk/ba2f0da49bf2f571d6bf606d96f289d7
Shevchuk
1
Funktioniert hervorragend unter Ubuntu, nachdem der Pfad verwendet grep -Eund hinzugefügt wurde /bin(siehe Bearbeiten). Sie können
jederzeit
3

Ich brauchte dies auch für einige systemweite Benachrichtigungen. Hier ist meine Lösung. Es scannt / prozessiert, um alle Sitzungsbusse zu finden, und führt dann auf jedem davon eine Benachrichtigung aus (einmal pro Bus). Alle Argumente werden unverändert an real notify-send übergeben.

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

In Ubuntu 16.04 wollte ich Benachrichtigungen von einem Skript, das als root von crontab ausgeführt wird. Nach dem Setzen der Umgebungsvariablen hat sudo -u $useres aus irgendeinem Grund nicht funktioniert, sh -c "..." $userfunktioniert aber .

Also benutze ich jetzt diese Funktion:

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 
}

Wie Sie die Variable DBUS_SESSION_BUS_ADDRESS finden, hängt wahrscheinlich von Ihrer Verteilung ab. In Ubuntu 16.04 ist es in /run/user/$UID/dbus-session, die einfach bezogen werden kann. id -uwird in der obigen Funktion verwendet, um die UID des von zurückgegebenen Benutzernamens zu ermitteln who.

mivk
quelle
Wie benutzt man es? Kannst du mir helfen?
Elgolondrino
0

Hier ist ein Update von Andys Skript: Die Art und Weise, wie das ermittelt wurde, DBUS_SESSION_BUS_ADDRESSfunktioniert unter Centos 7 nicht. Außerdem listete der whoBefehl einige Sitzungen aus irgendeinem Grund nicht auf, sodass ich ps auxstattdessen die Ausgabe analysiere . In diesem Skript wird davon ausgegangen nxagent, dass Benutzer mit X2GO ( ) angemeldet sind , die Anpassung für andere Fälle sollte jedoch einfach sein.

#!/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
quelle
-1
users=$(who | awk '{print $1}')

for user in $users<br>
do
        DISPLAY=:0 sudo -u $user notify-send "hello!!"
done
Vicent
quelle