Mostra una notifica su tutti i display X in esecuzione


16

Usando la riga di comando, vorrei mostrare una notifica su ogni display X in esecuzione. (e console in esecuzione)

Qualcosa di simile a:

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

C'è un programma che lo farà? In caso contrario, questo può essere implementato con bash?


1
Per le persone che vengono qui anni dopo, c'è una semplice funzione notification_all in questa risposta che funziona in Ubuntu 16.04 e può essere usata negli script avviati da root.
marzo

Risposte:


16

Puoi inviare un messaggio a tutte le console con il wall dei comandi.

Per l'invio di notifiche in X è presente notifica-invio che invia una notifica all'utente corrente sul display corrente. (Dalla tua domanda, immagino tu lo sappia già.) Puoi basarti su questo con un po 'di scripting bash. Fondamentalmente devi scoprire quali utenti sono su quali X-Display. Una volta ottenute queste informazioni, puoi utilizzare Notify-Send in questo modo:

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

Dove fschmitt è l'utente sul display 0. È possibile analizzare l'output del comando "who" per trovare tutti gli utenti e i loro display. L'output è simile al seguente

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

Vedete, ci sono due utenti che eseguono sessioni X, markmerk3 sul display 0 e seamonkey sul display 1. Penso che sia necessario eseguire grep per tty [0-9] *, quindi assicurarsi che alla fine della riga ci sia (: [0 -9.] *) Per eliminare gli accessi alla console ed estrarre l'id di visualizzazione dalla stringa tra parentesi.


2
Il comando whoti dice chi ha effettuato l'accesso e su quale X visualizza l'accesso. Potrebbe essere necessario filtrarlo in qualche modo.
tante

1
Mentre è probabilmente meglio usare un loop in uno script di shell, puoi sempre fare qualcosa del genere who | awk '/\(:[0-9]+\)/ {gsub("[:|(|)]","");print "DISPLAY=:"$5 " sudo -u " $1 " notify-send \"Message\""}' | bash. Inoltre, potresti voler vedere unix.stackexchange.com/questions/1596/…
Steven D

8

Questo thread è un po 'vecchio, mi dispiace, ma spero di poter ancora aggiungere qualcosa di utile all'argomento. (anche Josef Kufner ha scritto una bella sceneggiatura, era un po 'troppo lunga per i miei gusti e usa PHP)

Avevo anche bisogno di uno strumento come descritto nella domanda originale (per inviare un messaggio a tutti gli utenti X attivi). E sulla base delle risposte qui, ho scritto questo piccolo script solo bash, che cerca gli utenti X attivi (usando 'chi') e quindi eseguendo notifica-invio per ogni utente attivo.

E il meglio: puoi usare il mio script esattamente come "notification-send", con tutti i suoi parametri! ;-)

notify-send-tutto:

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

Copia il codice sopra in un file chiamato "notification-send-all", rendilo eseguibile e copialo in / usr / local / bin o / usr / bin (come preferisci). Quindi eseguilo ad es. Come root in una sessione della console come questa:

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

Lo sto usando da diversi mesi, su macchine diverse, e finora non ho avuto problemi, e l'ho testato con i desktop MATE e Cinnamon. Eseguendolo anche con successo all'interno di cron e anacron.

Ho scritto questo script per / sotto ArchLinux, quindi per favore dimmi se hai problemi su altre distribuzioni o desktop Linux.


|egrep?? egrep è un comando?
Sw0ut,

@ Sw0ut, egrep è davvero un comando. Ma nella pagina man di grep (1) dice che egrep, fgrep e rgrep sono deprecati e si raccomanda l'uso delle loro forme equivalenti "grep -E", "grep -F" e "grep -r".
rsuarez,

Invece di awk '{print $1$5}'è meglio usarlo awk '{print $1$NF}', in modo che non si rompa in alcuni locali in cui la data è formattata con spazi (ad esempio Jun 3invece di 2017-06-03). Ecco anche una versione per avvisare l'utente specifico anziché tutti gli utenti: gist.github.com/shvchk/ba2f0da49bf2f571d6bf606d96f289d7
Shevchuk

1
Funziona magnificamente su Ubuntu dopo aver usato grep -Ee aggiunto /binil percorso (vedi la modifica). Sentiti libero di tornare indietro se ti
opponi

3

Ne avevo bisogno anche per alcune notifiche a livello di sistema. Ecco la mia soluzione Esegue la scansione / proc per trovare tutti i bus di sessione e quindi esegue notifica-invio su ciascuno di essi (una volta per bus). Tutti gli argomenti vengono passati invariati alla notifica-invio reale.

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

In Ubuntu 16.04, volevo le notifiche da uno script in esecuzione come root da crontab. Dopo aver impostato le variabili di ambiente, sudo -u $usernon ha funzionato per qualche motivo, ma sh -c "..." $userfunziona.

Quindi ora uso questa funzione:

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 
}

Come trovare la variabile DBUS_SESSION_BUS_ADDRESS probabilmente dipende dalla tua distribuzione. In Ubuntu 16.04, è presente /run/user/$UID/dbus-session, che può essere semplicemente reperito. id -uviene utilizzato nella funzione sopra per ottenere l'UID dal nome utente restituito da who.


Come usarlo? Mi potete aiutare?
elgolondrino

0

Ecco un aggiornamento dello script di Andy: il modo in cui ha determinato DBUS_SESSION_BUS_ADDRESSche non funziona su Centos 7. Inoltre il whocomando non ha elencato alcune sessioni per qualche motivo, quindi analizzo ps auxinvece l' output. Questo script presuppone che gli utenti abbiano effettuato l'accesso utilizzando X2GO ( nxagent), ma dovrebbe essere semplice da regolare per altri casi.

#!/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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.