ti-enxame.com

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

Usando a linha de comando, 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? Se não, isso pode ser implementado com o bash?

16
Stefan

Você pode enviar uma mensagem para todos os consoles com a parede de comando.

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

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

Onde fschmitt é o usuário no display 0. Você pode analisar a saída do comando "who" para localizar todos os usuários e seus displays. A saída é parecida com esta

[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, há dois usuários executando sessões X, markmerk3 na tela 0 e seamonkey na tela 1. Acho que você precisa grep for tty [0-9] * e 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 os parênteses.

16
fschmitt

Este tópico é um pouco antigo, desculpe, mas espero ainda poder adicionar algo útil ao tópico. (também Josef Kufner escreveu um bom script, era um pouco longo 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 este pequeno script somente bash, que procura por usuários X ativos (usando 'quem') e, em seguida, execute o notificar-enviar 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 "[email protected]"
done

Copie o código acima em um arquivo chamado "notificar-enviar-todos", torná-lo executável e copiá-lo para / usr/local/bin ou / usr/bin (como você gosta). 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 há vários meses, em máquinas diferentes, e não tive nenhum problema até agora, e testei com MATE e desktops Cinnamon. Também executando com sucesso dentro do cron e anacron.

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

10
Andy

No Ubuntu 16.04, eu queria notificações de um script rodando como root do crontab. Depois de definir as variáveis ​​de ambiente, Sudo -u $user não funcionou por algum motivo, mas sh -c "..." $user funciona.

Então, agora 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, está em /run/user/$UID/dbus-session, que pode simplesmente ser obtido. id -u é usado na função acima para obter o UID do nome de usuário retornado por who.

3
mivk

Eu precisava disso também para algumas notificações de todo o sistema. Aqui está minha solução. Ele varre/proc para encontrar todos os barramentos de sessão e, em seguida, executa notificar-enviar em cada um deles (uma vez por barramento). Todos os argumentos são passados ​​inalterados para o 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);
                        }
                }
        }
' -- "[email protected]"
3
Josef Kufner

Aqui está uma atualização do script de Andy: A maneira como determinou o DBUS_SESSION_BUS_ADDRESS não funciona no Centos 7. Além disso, o comando who não listou algumas sessões por algum motivo, então analiso o ps aux saída ao invés. Este script assume que os usuários estão logados usando 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
0
jpf