実行中のすべての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-Displaysを使用しているかを調べる必要があります。この情報を取得したら、次のようにnotify-sendを使用できます。

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セッションを実行している2人のユーザー、ディスプレイ0のmarkmerk3とディスプレイ1のseamonkeyがいることがわかります。 -9。] *)コンソールログインを取り除き、括弧内の文字列から表示IDを抽出します。


2
このコマンドwhoは、誰がログインしていて、どのXにそのログインが表示されているかを示します。多少フィルタリングする必要があるかもしれません。
タント

1
シェルスクリプトでループを使用することをお勧めしますが、常に次のようなことができますwho | awk '/\(:[0-9]+\)/ {gsub("[:|(|)]","");print "DISPLAY=:"$5 " sudo -u " $1 " notify-send \"Message\""}' | bash。また、unix.stackexchange.com / questions / 1596
スティーブンD

8

このスレッドは少し古いですが、申し訳ありませんが、このトピックに役立つものを追加できることを願っています。(また、Josef Kufnerは素敵なスクリプトを作成しましたが、私の好みには少し長すぎました。PHPを使用しています)

元の質問で説明されているツールも必要でした(すべてのアクティブなXユーザーにメッセージを送信するため)。そして、ここでの回答に基づいて、アクティブなXユーザー(「who」を使用)を検索し、すべてのアクティブなユーザーに対してnotify-sendを実行するこの小さなbash専用スクリプトを作成しました。

そして最高:私のスクリプトを「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」と同等の形式を使用することをお勧めします。
ルアレス

代わりに、awk '{print $1$5}'を使用する方が適切です。これによりawk '{print $1$NF}'、日付がスペースでフォーマットされているロケール(たとえばJun 32017-06-03)で壊れないようになります。また、すべてのユーザーではなく特定のユーザーに通知するバージョンもあります:gist.github.com/shvchk/ba2f0da49bf2f571d6bf606d96f289d7
Shevchuk

1
パスを使用grep -Eして追加/binした後、Ubuntu上で見事に動作します(編集を参照)。あなたがオブジェクトの場合は元に戻す気軽
SERV-INC

3

システム全体の通知にもこれが必要でした。これが私の解決策です。/ procをスキャンしてすべてのセッションバスを見つけ、各バスでnotify-sendを実行します(バスごとに1回)。すべての引数は変更されずに実際の通知送信に渡されます。

#!/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では、crontabからrootとして実行されているスクリプトからの通知が必要でした。環境変数を設定した後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ます。


どうやって使うのですか?手伝って頂けますか?
-elgolondrino

0

Andyのスクリプトの更新は次のとおりですDBUS_SESSION_BUS_ADDRESS。Centos7では動作を決定する方法が機能しません。また、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

-1
users=$(who | awk '{print $1}')

for user in $users<br>
do
        DISPLAY=:0 sudo -u $user notify-send "hello!!"
done
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.