Mostrar una notificación en todas las pantallas X en ejecución

16

Usando la línea de comando, me gustaría mostrar una notificación en cada pantalla X en ejecución. (y ejecutando la consola)

Algo como:

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

¿Hay algún programa que haga esto? Si no, ¿se puede implementar con bash?

Stefan
fuente
1
Para las personas que vienen aquí años después, hay una función simple notify_all en esta respuesta que funciona en Ubuntu 16.04, y se puede usar en scripts iniciados por root.
mivk

Respuestas:

16

Puede enviar un mensaje a todas las consolas con el panel de comandos.

Para enviar notificaciones bajo X, hay un envío de notificaciones que envía una notificación al usuario actual en la pantalla actual. (De su pregunta, supongo que ya conoce esta.) Puede construir sobre esto con algunas secuencias de comandos bash. Básicamente, debe averiguar qué usuarios están en qué pantallas X. Una vez que obtenga esta información, puede usar la opción de enviar y enviar notificaciones de la siguiente manera:

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

Donde fschmitt es el usuario en la pantalla 0. Puede analizar la salida del comando "who" para encontrar todos los usuarios y sus pantallas. La salida se ve así

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

Verá, hay dos usuarios ejecutando sesiones X, markmerk3 en la pantalla 0 y seamonkey en la pantalla 1. Creo que necesita grep para tty [0-9] * y luego asegurarse de que al final de la línea hay (: [0 -9.] *) Para deshacerse de los inicios de sesión de la consola y extraer la identificación de la pantalla de la cadena entre paréntesis.

fschmitt
fuente
2
El comando whole dice quién ha iniciado sesión y en qué pantalla X está ese inicio de sesión. Es posible que deba filtrarlo un poco.
tante
1
Si bien es probable que sea mejor usar un bucle en un script de shell, siempre podría hacer algo así who | awk '/\(:[0-9]+\)/ {gsub("[:|(|)]","");print "DISPLAY=:"$5 " sudo -u " $1 " notify-send \"Message\""}' | bash. Además, es posible que desee ver unix.stackexchange.com/questions/1596/…
Steven D
8

Este hilo es un poco viejo, lo siento, pero espero poder agregar algo útil al tema. (también Josef Kufner escribió un buen script, fue demasiado largo para mi gusto y usa PHP)

También necesitaba una herramienta como se describe en la pregunta original (para enviar un mensaje a todos los usuarios X activos). Y en base a las respuestas aquí, escribí este pequeño script solo para bash, que busca usuarios X activos (usando 'who'), y luego ejecuta notificar-enviar para cada usuario activo.

Y lo mejor: ¡puedes usar mi script exactamente como "notificar-enviar", con todos sus parámetros! ;-)

notificar-enviar-todo:

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

Copie el código anterior en un archivo llamado "notify-send-all", hágalo ejecutable y cópielo en / usr / local / bin o / usr / bin (como desee). Luego ejecútelo, por ejemplo, como root en una sesión de consola como esta:

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

Lo uso desde hace varios meses, en diferentes máquinas, y hasta ahora no tuve ningún problema, y ​​lo probé con los escritorios MATE y Cinnamon. También lo ejecutó con éxito dentro de cron y anacron.

Escribí este script para / bajo ArchLinux, así que dígame si tiene problemas en otras distribuciones de Linux o escritorios.

Andy
fuente
|egrep?? ¿egrep es un comando?
Sw0ut
@ Sw0ut, egrep es de hecho un comando. Pero en la página de manual de grep (1) dice que egrep, fgrep y rgrep están en desuso, y se recomienda el uso de sus formas equivalentes "grep -E", "grep -F" y "grep -r".
rsuarez
En lugar de awk '{print $1$5}'eso, es mejor usarlo awk '{print $1$NF}', para que no se rompa en algunas configuraciones regionales donde la fecha está formateada con espacios (por ejemplo, en Jun 3lugar de 2017-06-03). Aquí también hay una versión para notificar a un usuario específico en lugar de a todos los usuarios: gist.github.com/shvchk/ba2f0da49bf2f571d6bf606d96f289d7
Shevchuk
1
Funciona espléndidamente en Ubuntu después de usar grep -Ey agregar /bina la ruta (ver la edición). Siéntase libre de revertir si se opone
serv-inc
3

También necesitaba esto para algunas notificaciones de todo el sistema. Aquí está mi solución. Escanea / procesa para encontrar todos los buses de sesión y luego ejecuta notificar-enviar en cada uno de ellos (una vez por bus). Todos los argumentos se pasan sin cambios a la notificación de envío real.

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

En Ubuntu 16.04, quería notificaciones de un script que se ejecutaba como root desde crontab. Después de configurar las variables de entorno, sudo -u $userno funcionó por alguna razón, pero sh -c "..." $userfunciona.

Así que ahora uso esta función:

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ómo encontrar la variable DBUS_SESSION_BUS_ADDRESS probablemente depende de su distribución. En Ubuntu 16.04, está en /run/user/$UID/dbus-session, que simplemente puede obtenerse. id -use usa en la función anterior para obtener el UID del nombre de usuario devuelto por who.

mivk
fuente
¿Cómo usarlo? ¿Me puedes ayudar?
elgolondrino 01 de
0

Aquí hay una actualización del script de Andy: la forma en que determinó DBUS_SESSION_BUS_ADDRESSque no funciona en Centos 7. Además, el whocomando no enumeró algunas sesiones por alguna razón, por lo que analizo el ps auxresultado en su lugar. Este script asume que los usuarios han iniciado sesión con X2GO ( nxagent), pero debería ser sencillo de ajustar para otros casos.

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

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