Показать уведомление на всех запущенных дисплеях X

16

Используя командную строку, я хотел бы показывать уведомление на каждом запущенном дисплее X. (и работает консоль)

Что-то вроде:

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

Есть ли программа, которая сделает это? Если нет, то можно ли это реализовать с помощью bash?

Стефан
источник
1
Для людей, приезжающих сюда спустя годы, в этом ответе есть простая функция notify_all, которая работает в Ubuntu 16.04 и может использоваться в сценариях, запускаемых root.
Mivk

Ответы:

16

Вы можете отправить сообщение на все консоли с помощью командной стены.

Для отправки уведомлений под X есть notify-send, которая отправляет уведомление текущему пользователю на текущем дисплее. (Из вашего вопроса, я думаю, вы уже знаете это.) Вы можете развить это с помощью некоторых скриптов bash. В основном вы должны выяснить, какие пользователи на каких X-дисплеях. После того, как вы получили эту информацию, вы можете использовать уведомление-отправить, как это:

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

Где fschmitt - это пользователь на дисплее 0. Вы можете проанализировать вывод команды "who", чтобы найти всех пользователей и их дисплеи. Вывод выглядит так

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

Видите ли, есть два пользователя, выполняющие сеансы X, markmerk3 на дисплее 0 и seamonkey на дисплее 1. Я думаю, вам нужно выполнить grep для tty [0-9] *, а затем убедиться, что в конце строки есть (: [0 -9.] *) Чтобы избавиться от логинов консоли и извлечь отображаемый идентификатор из строки в скобках.

fschmitt
источник
2
Команда whoсообщает вам, кто вошел в систему и на каком дисплее X отображается этот вход. Возможно, вам просто придется его отфильтровать.
танте
1
Хотя, вероятно, лучше всего использовать цикл в сценарии оболочки, вы всегда можете сделать что-то подобное who | awk '/\(:[0-9]+\)/ {gsub("[:|(|)]","");print "DISPLAY=:"$5 " sudo -u " $1 " notify-send \"Message\""}' | bash. Кроме того, вы можете захотеть увидеть unix.stackexchange.com/questions/1596/…
Стивен Д.
8

Эта ветка немного старая, извините, но я надеюсь, что смогу добавить что-то полезное в тему. (также Йозеф Куфнер написал хороший сценарий, на мой вкус он был слишком длинным и использует PHP)

Мне также был нужен инструмент, как описано в исходном вопросе (чтобы отправить сообщение всем активным пользователям X). И основываясь на ответах здесь, я написал этот небольшой скрипт только для bash, который ищет активных пользователей X (используя «кто»), а затем запускает команду notify-send для каждого активного пользователя.

И самое лучшее: вы можете использовать мой скрипт в точности как «notify-send» со всеми его параметрами! ;-)

уведомительный отправить-всего:

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

Скопируйте приведенный выше код в файл с именем «notify-send-all», сделайте его исполняемым и скопируйте его в / usr / local / bin или / usr / bin (как вам нравится). Затем запустите его, например, от имени пользователя root в сеансе консоли следующим образом:

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

Я использую его уже несколько месяцев на разных машинах, и у меня до сих пор не было проблем, и я протестировал его на настольных компьютерах MATE и Cinnamon. Также успешно работает в cron и anacron.

Я написал этот скрипт для / под ArchLinux, поэтому, пожалуйста, сообщите мне, если у вас проблемы с другими дистрибутивами Linux или рабочими столами.

Энди
источник
|egrep?? такое egrep команда?
Sw0ut
@ Sw0ut, egrep - это действительно команда. Но в справочной странице grep (1) говорится, что egrep, fgrep и rgrep устарели, и рекомендуется использовать их эквивалентные формы "grep -E", "grep -F" и "grep -r".
rsuarez
Вместо awk '{print $1$5}'этого лучше использовать awk '{print $1$NF}', чтобы не нарушать некоторые локали, где дата форматируется с пробелами (например, Jun 3вместо 2017-06-03). Вот также версия для уведомления конкретного пользователя вместо всех пользователей: gist.github.com/shvchk/ba2f0da49bf2f571d6bf606d96f289d7
Шевчук
1
Прекрасно работает в Ubuntu после использования grep -Eи добавления /binк пути (см. Редактирование). Не стесняйтесь вернуться, если вы возражаете
serv-inc
3

Мне это тоже нужно было для некоторых системных уведомлений. Вот мое решение. Он просматривает / proc, чтобы найти все сеансовые шины, а затем выполняет уведомление-отправку для каждой из них (один раз для каждой шины). Все аргументы передаются без изменений для реального уведомления-отправки.

#!/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);
                        }
                }
        }
' -- "$@"
Йозеф Куфнер
источник
1

В Ubuntu 16.04 я хотел получать уведомления от скрипта, работающего от имени пользователя root, из crontab. После установки переменных среды sudo -u $userпо какой-то причине sh -c "..." $userне работал , но работает.

Итак, я сейчас использую эту функцию:

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 
}

Как найти переменную DBUS_SESSION_BUS_ADDRESS, вероятно, зависит от вашего дистрибутива. В Ubuntu 16.04 он есть /run/user/$UID/dbus-session, который можно просто получить. id -uиспользуется в функции выше, чтобы получить UID из имени пользователя, возвращаемого who.

mivk
источник
Как это использовать? Вы можете помочь мне?
elgolondrino
0

Вот обновление скрипта Энди: способ, которым он определил DBUS_SESSION_BUS_ADDRESS, не работает на Centos 7. Также whoкоманда по какой-то причине не перечислила некоторые сеансы, поэтому ps auxвместо этого я анализирую вывод. В этом сценарии предполагается, что пользователи вошли в систему с помощью X2GO ( nxagent), но его следует легко настроить для других случаев.

#!/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
источник
-1
users=$(who | awk '{print $1}')

for user in $users<br>
do
        DISPLAY=:0 sudo -u $user notify-send "hello!!"
done
Vicent
источник