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?
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.
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.
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
.
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]"
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