С сокетами читают каналы или ttys, (), и запись () может передать меньше, чем требуемый размер, поэтому при использовании dd на них, Вам нужен флаг fullblock. С регулярными файлами и блочными устройствами однако, существует только два раза, когда они могут сделать короткое чтение-запись: когда Вы достигаете EOF, или если существует ошибка. Поэтому более старые реализации dd без флага fullblock было безопасно использовать для дискового дублирования.
Можно отправить сообщение во все консоли со стеной команды.
Для отправки уведомлений под X существует, уведомляют - отправляют, который отправляет уведомление текущему пользователю на текущем дисплее. (От Вашего вопроса я предполагаю, что Вы уже знаете этого.) Можно положиться на это с некоторыми сценариями удара. В основном необходимо узнать, какие пользователи включены который X-дисплеи. После того как Вы получили эту информацию, которую можно использовать, уведомляют - отправляют как это:
DISPLAY=:0 sudo -u fschmitt notify-send "Message"
Где fschmitt является пользователем в дисплее 0. Можно проанализировать вывод, "кто" управляет для нахождения всех пользователей и их дисплеев. Вывод похож на это
[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]. *) избавиться от консольных логинов и извлечь идентификатор дисплея из строки между круглыми скобками.
Мне это тоже нужно для некоторых общесистемных уведомлений. Вот мое решение. Он сканирует / proc, чтобы найти все сеансовые шины, а затем выполняет notify-send на каждой из них (один раз на шину). Все аргументы передаются в неизменном виде в настоящий notify-send.
#!/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);
}
}
}
' -- "$@"
users=$(who | awk '{print $1}')
for user in $users<br>
do
DISPLAY=:0 sudo -u $user notify-send "hello!!"
done
Эта тема немного старая, извините, но я надеюсь, что все еще могу добавить что-то полезное в тему. (также Йозеф Куфнер написал хороший скрипт, он был просто немного слишком длинным на мой вкус, и он использует PHP)
Мне также нужен был инструмент, как описано в оригинальном вопросе (чтобы отправить сообщение всем активным X-пользователям). И основываясь на ответах здесь, я написал этот небольшой скрипт только bash, который ищет активных X-пользователей (используя «кто»), а затем запускает notify-send для каждого активного пользователя.
И самое лучшее: вы можете использовать мой скрипт точно так же, как "notify-send", со всеми его параметрами! ;-)
notify-send-all:
#!/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 «Предупреждение» «Судно на воздушной подушке полно угрей!»
Я использую его уже несколько месяцев, на разных машинах, и до сих пор не было никаких проблем, и я протестировал его с настольными компьютерами MATE и Cinnamon. Также успешно запускается его внутри cron и anacron.
Я написал этот скрипт для / под ArchLinux, поэтому, пожалуйста, скажите мне, если у вас возникли проблемы на других дистрибутивах Linux или настольных компьютерах.
В 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
.
Вот обновление скрипта Энди. :То, как он определил 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
who
говорит Вам, кто зарегистрирован и на котором, X дисплеев что вход в систему. Вам просто, возможно, придется отфильтровать его несколько. – tante 08.10.2010, 12:49who | awk '/\(:[0-9]+\)/ {gsub("[:|(|)]","");print "DISPLAY=:"$5 " sudo -u " $1 " notify-send \"Message\""}' | bash
. Кроме того, Вы могли бы хотеть видеть unix.stackexchange.com/questions/1596 / … – Steven D 08.10.2010, 18:34