Afficher une notification sur tous les écrans X en cours d'exécution

16

En utilisant la ligne de commande, je voudrais afficher une notification sur chaque écran X en cours d'exécution. (et console en cours d'exécution)

Quelque chose comme:

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

Existe-t-il un programme qui fera cela? Sinon, cela peut-il être implémenté avec bash?

Stefan
la source
1
Pour les personnes qui viennent ici des années plus tard, il y a une simple fonction notify_all dans cette réponse qui fonctionne dans Ubuntu 16.04 et peut être utilisée dans des scripts démarrés par root.
mivk

Réponses:

16

Vous pouvez envoyer un message à toutes les consoles avec le mur de commandes.

Pour envoyer des notifications sous X, il y a notification-send qui envoie une notification à l'utilisateur actuel sur l'affichage actuel. (D'après votre question, je suppose que vous connaissez déjà celle-ci.) Vous pouvez vous en inspirer avec des scripts bash. Fondamentalement, vous devez savoir quels utilisateurs sont sur quels X-Displays. Une fois que vous avez obtenu ces informations, vous pouvez utiliser notify-send comme ceci:

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

Où fschmitt est l'utilisateur à l'affichage 0. Vous pouvez analyser la sortie de la commande "who" pour trouver tous les utilisateurs et leurs affichages. La sortie ressemble à ceci

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

Vous voyez, il y a deux utilisateurs qui exécutent des sessions X, markmerk3 à l'affichage 0 et seamonkey à l'affichage 1. Je pense que vous devez chercher pour tty [0-9] * puis vous assurer qu'à la fin de la ligne il y a (: [0 -9.] *) Pour se débarrasser des connexions à la console et extraire l'ID d'affichage de la chaîne entre parenthèses.

fschmitt
la source
2
La commande whovous indique qui est connecté et sur quel X affiche cette connexion. Vous pourriez juste devoir le filtrer quelque peu.
tante
1
Bien qu'il soit probablement préférable d'utiliser simplement une boucle dans un script shell, vous pouvez toujours faire quelque chose comme who | awk '/\(:[0-9]+\)/ {gsub("[:|(|)]","");print "DISPLAY=:"$5 " sudo -u " $1 " notify-send \"Message\""}' | bash. En outre, vous voudrez peut-être voir unix.stackexchange.com/questions/1596/…
Steven D
8

Ce fil est un peu ancien, désolé, mais j'espère pouvoir encore ajouter quelque chose d'utile au sujet. (Josef Kufner a également écrit un joli script, c'était juste un peu trop long à mon goût, et il utilise PHP)

J'avais également besoin d'un outil tel que décrit dans la question d'origine (pour envoyer un message à tous les utilisateurs X actifs). Et sur la base des réponses ici, j'ai écrit ce petit script bash uniquement, qui recherche les utilisateurs X actifs (en utilisant «qui»), puis en exécutant notify-send pour chaque utilisateur actif.

Et le meilleur: vous pouvez utiliser mon script exactement comme "notify-send", avec tous ses paramètres! ;-)

notifier-envoyer-tout:

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

Copiez le code ci-dessus dans un fichier nommé "notify-send-all", rendez-le exécutable et copiez-le dans / usr / local / bin ou / usr / bin (comme vous le souhaitez). Ensuite, exécutez-le par exemple en tant que root dans une session de console comme ceci:

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

Je l'utilise depuis plusieurs mois maintenant, sur différentes machines, et je n'ai eu aucun problème jusqu'à présent, et je l'ai testé avec les ordinateurs de bureau MATE et Cinnamon. Également exécuté avec succès dans cron et anacron.

J'ai écrit ce script pour / sous ArchLinux, alors dites-moi si vous rencontrez des problèmes sur une autre distribution Linux ou un autre bureau.

Andy
la source
|egrep?? egrep est-il une commande?
Sw0ut
@ Sw0ut, egrep est en effet une commande. Mais dans la page de manuel de grep (1) indique que egrep, fgrep et rgrep sont déconseillés, et l'utilisation de leurs formes équivalentes "grep -E", "grep -F" et "grep -r" est recommandée.
rsuarez
Au lieu de cela, awk '{print $1$5}'il est préférable d'utiliser awk '{print $1$NF}', de sorte qu'il ne se casse pas sur certains paramètres régionaux où la date est formatée avec des espaces (par exemple Jun 3au lieu de 2017-06-03). Voici également une version pour avertir un utilisateur spécifique au lieu de tous les utilisateurs: gist.github.com/shvchk/ba2f0da49bf2f571d6bf606d96f289d7
Shevchuk
1
Fonctionne à merveille sur Ubuntu après avoir utilisé grep -Eet ajouté /binau chemin (voir la modification). N'hésitez pas à revenir si vous vous
opposez
3

J'en avais également besoin pour certaines notifications à l'échelle du système. Voici ma solution. Il scanne / proc pour trouver tous les bus de session, puis il exécute notify-send sur chacun d'eux (une fois par bus). Tous les arguments sont passés inchangés en véritable notification-envoi.

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

Dans Ubuntu 16.04, je voulais des notifications à partir d'un script exécuté en tant que root à partir de crontab. Après avoir défini les variables d'environnement,sudo -u $user n'a pas fonctionné pour une raison quelconque, mais sh -c "..." $userfonctionne.

J'utilise donc maintenant cette fonction:

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 
}

Comment trouver la variable DBUS_SESSION_BUS_ADDRESS dépend probablement de votre distribution. Dans Ubuntu 16.04, c'est dans /run/user/$UID/dbus-session, qui peut simplement être sourcé. id -uest utilisé dans la fonction ci-dessus pour obtenir l'UID à partir du nom d'utilisateur renvoyé par who.

mivk
la source
Comment l'utiliser? Pouvez-vous m'aider?
elgolondrino
0

Voici une mise à jour du script d'Andy: La façon dont il a déterminé que DBUS_SESSION_BUS_ADDRESScela ne fonctionne pas sur Centos 7. De plus, la whocommande n'a pas répertorié certaines sessions pour une raison quelconque, donc j'analyse la ps auxsortie à la place. Ce script suppose que les utilisateurs sont connectés à l'aide de X2GO ( nxagent), mais il devrait être simple de s'adapter à d'autres cas.

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

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