Mostrar uma notificação em todos os monitores X em execução

16

Usando a linha de comando, eu gostaria de mostrar uma notificação em cada exibição do X em execução. (e console em execução)

Algo como:

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

Existe um programa que fará isso? Caso contrário, isso pode ser implementado com o bash?

Stefan
fonte
11
Para as pessoas que chegam aqui anos depois, há uma função simples notify_all nesta resposta que funciona no Ubuntu 16.04 e pode ser usada em scripts iniciados pelo root.
Mvk

Respostas:

16

Você pode enviar uma mensagem para todos os consoles com o mural de comandos.

Para enviar notificações em X, há um envio de notificação que envia uma notificação para o usuário atual na exibição atual. (Com base na sua pergunta, acho que você já conhece essa.) Você pode desenvolver isso com alguns scripts bash. Basicamente, você precisa descobrir quais usuários estão em quais X-Displays. Depois de obter essas informações, você pode usar o envio de notificação assim:

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

Onde fschmitt é o usuário na tela 0. Você pode analisar a saída do comando "who" para encontrar todos os usuários e suas telas. A saída é assim

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

Veja bem, existem dois usuários executando sessões X, markmerk3 no display 0 e seamonkey no display 1. Acho que você precisa grep para tty [0-9] * e depois garantir que no final da linha haja (: [0 -9.] *) Para se livrar dos logins do console e extrair o ID de exibição da string entre parênteses.

fschmitt
fonte
2
O comando whoinforma quem está logado e em qual X exibe esse logon. Você pode ter que filtrá-lo um pouco.
tante
11
Embora seja provavelmente melhor usar apenas um loop em um script de shell, você sempre pode fazer algo assim who | awk '/\(:[0-9]+\)/ {gsub("[:|(|)]","");print "DISPLAY=:"$5 " sudo -u " $1 " notify-send \"Message\""}' | bash. Além disso, você pode querer ver unix.stackexchange.com/questions/1596/…
Steven D
8

Este tópico é um pouco antigo, desculpe, mas espero ainda poder adicionar algo útil ao tópico. (também Josef Kufner escreveu um bom roteiro, foi um pouco longo demais para o meu gosto e usa PHP)

Eu também precisava de uma ferramenta, conforme descrito na pergunta original (para enviar uma mensagem a todos os usuários X ativos). E com base nas respostas aqui, escrevi esse pequeno script somente bash, que procura usuários X ativos (usando 'who') e, em seguida, executando o envio de notificação para cada usuário ativo.

E o melhor: você pode usar meu script exatamente como "notificar-enviar", com todos os seus parâmetros! ;-)

notificar-enviar-tudo:

#!/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 o código acima em um arquivo chamado "notify-send-all", torne-o executável e copie-o para / usr / local / bin ou / usr / bin (como desejar). Em seguida, execute-o, por exemplo, como root em uma sessão de console como esta:

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

Estou usando-o há vários meses, em máquinas diferentes, e não tive nenhum problema até agora, e testei-o com os desktops MATE e Cinnamon. Também executá-lo com sucesso no cron e no anacron.

Eu escrevi esse script para / no ArchLinux, então, por favor, diga-me se você está tendo problemas em outras distribuições ou desktops Linux.

Andy
fonte
|egrep?? O egrep é um comando?
Sw0ut
@ Sw0ut, egrep é realmente um comando. Mas na página de manual do grep (1) diz que egrep, fgrep e rgrep estão obsoletos, e o uso de suas formas equivalentes "grep -E", "grep -F" e "grep -r" é recomendado.
rsuarez 21/05
Em vez disso awk '{print $1$5}', é melhor usá- awk '{print $1$NF}'lo, para que não seja interrompido em alguns locais onde a data é formatada com espaços (por exemplo, em Jun 3vez de 2017-06-03). Aqui é também uma versão para notificar usuário específico em vez de todos os usuários: gist.github.com/shvchk/ba2f0da49bf2f571d6bf606d96f289d7
Shevchuk
11
Funciona esplendidamente no Ubuntu depois de usar grep -Ee adicionar /binao caminho (veja a edição). Sinta-se livre para reverter se opor
serv-inc
3

Eu também precisava disso para algumas notificações em todo o sistema. Aqui está a minha solução. Ele examina / proc para encontrar todos os barramentos de sessão e, em seguida, executa o envio de notificação em cada um deles (uma vez por barramento). Todos os argumentos são passados ​​inalterados para envio de notificaçã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
fonte
1

No Ubuntu 16.04, eu queria notificações de um script executado como root no crontab. Depois de definir as variáveis ​​de ambiente, sudo -u $usernão funcionou por algum motivo, massh -c "..." $user funciona.

Então agora eu uso esta função:

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 
}

Como encontrar a variável DBUS_SESSION_BUS_ADDRESS provavelmente depende da sua distribuição. No Ubuntu 16.04, ele está dentro /run/user/$UID/dbus-session, o que pode ser simplesmente obtido. id -ué usado na função acima para obter o UID do nome de usuário retornado por who.

mivk
fonte
Como usá-lo? Pode me ajudar?
Elgolondrino 01/04
0

Aqui está uma atualização do script de Andy: A maneira como ela determinou DBUS_SESSION_BUS_ADDRESSque não funciona no Centos 7. Além disso, o whocomando não listou algumas sessões por algum motivo, então analiso a ps auxsaída. Esse script pressupõe que os usuários estejam logados usando o X2GO ( nxagent), mas deve ser simples de ajustar para outros 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
fonte
-1
users=$(who | awk '{print $1}')

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