以root身份运行notify-send

25
我正在尝试在插入USB设备时获得通知,为此我使用udev规则跟踪插入时刻并从那里启动脚本。 脚本的想法是使用链接中所述的方法。 但是当尝试这样做时:
pids=`pgrep -u $user gnome-panel`

我发现gnome-panel不在那里了。搜索了一下解决方法,发现很多人抱怨这个解决方法已经不再起作用了。因此,我对这个问题进行了一些研究,并想出了这个(notify-plugin2.sh):

#!/bin/bash

DBUS_SESSION_BUS_ADDRESS=$(cat /home/user/.dbus/session-bus/$(cat /var/lib/dbus/machine-id)-0 | grep DBUS_SESSION_BUS_ADDRESS= | sed -e 's/DBUS_SESSION_BUS_ADDRESS=//')

su user Test.sh $DBUS_SESSION_BUS_ADDRESS

在切换到非root用户之前,获取DBUS_SESSION_BUS_ADDRESS。如果我没有理解错的话,这个语句是有效的。基于上面链接中的代码,我编写了另一个脚本(Test.sh)。

#!/bin/sh
user=`whoami`
title="Test"
timeout=30000
icon="~/Pictures/PicturesForPwrPoint/Pluged.jpg"

DBUS_SESSION_BUS_ADDRESS=$1

echo $DBUS_SESSION_BUS_ADDRESS
DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS \ notify-send -u low -t $timeout -i "$icon" "$title"

从其他代码中我所看到的,唯一的问题就是获取 DBUS_SESSION_BUS_ADDRESS。如果我没错的话,只要解决了这个问题,就可以实现弹出屏幕上的漂亮窗口了。
因此我的问题是:为什么启动时没有出现漂亮的弹出消息?
sudo sh notify-plugin2.sh

在报告错误部分查看此帖可能会很有趣。 https://bugs.launchpad.net/ubuntu/+source/libnotify/+bug/160598 - Sxubach
你的操作系统是什么? - deimus
Ubuntu 14.04 LTS 32-bit - Sxubach
1
请参考此答案,其中提供了一个在Ubuntu 16.04中可用的函数示例。 - mivk
8个回答

32

tomy的回答hongo对另一个问题的回答巧妙地结合起来,对我解决了这个问题。

function notify-send() {
    #Detect the name of the display in use
    local display=":$(ls /tmp/.X11-unix/* | sed 's#/tmp/.X11-unix/X##' | head -n 1)"

    #Detect the user using such display
    local user=$(who | grep '('$display')' | awk '{print $1}' | head -n 1)

    #Detect the id of the user
    local uid=$(id -u $user)

    sudo -u $user DISPLAY=$display DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$uid/bus notify-send "$@"
}

这个函数可以直接在任何以 root 用户身份运行的脚本中使用,作为 notify-send 命令的替代品。


谢谢。省了我一些时间。最后一行类似这样的代码可能有效。在Debian 9上测试通过:su - $user -c "DISPLAY=$display DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$uid/bus notify-send -i 'Title' 'Message'" - ColinWa
@ColinWa 函数中的最后一行实际上是带有参数的,你看到那个"$@"了吗?它允许你将参数 -i 'Title' 'Message' 直接传递给函数本身。它的作用是作为真正的 notify-send 的替代品。 - Fabio A.
1
我会更新第6行代码,加上 | head -n 1 (变成 local user=$(who | grep '('$display')' | awk '{print $1} | head -n 1'))。在我的机器上,它返回了8个不同的用户 :) - yosh
在 Fedora 35 中,user= ... 这行代码无法正常工作。我使用以下代码,而且我认为这更通用(很抱歉,我不知道如何在注释中获取多行代码格式)...function notify-send() { # 找到第一个 X socket local socket=$(ls /tmp/.X11-unix/* | head -n 1) # 提取显示名称、用户和用户 ID local display=":$(echo $socket | sed 's#/tmp/.X11-unix/X##')" local user uid read user uid <<< $(stat -c '%U %u' $socket) sudo -u $user DISPLAY=$display DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$uid/bus notify-send "$@" } - Core
对于我在 Arch Linux 上,这个方法可行(这个答案中的简化单行版本):sudo -u "$USER" DISPLAY=":$(find /tmp/.X11-unix -type s | grep -Pom1 '/tmp/.X11-unix/X\K\d+$')" "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u "$USER")/bus" /usr/bin/notify-send 'Notification heading' - tukusejssirs

18

要从作为root运行的后台脚本发送桌面通知
(用运行X的用户和用户ID分别替换X_user和X_userid):

sudo -u X_user DISPLAY=:0 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/X_userid/bus notify-send 'Hello world!' 'This is an example notification.'

这是来自于:https://wiki.archlinux.org/index.php/Desktop_notifications


1
这个一行代码非常方便,结合@hongo在另一个问题的回答(https://stackoverflow.com/a/40288615/566849)使用可以解决我的问题。 - Fabio A.

9
通知服务已更改为Ubuntu 14.04
现在被称为org.freedesktop.Notifications.service
您可以在此处查看有关Notification On Screen Display的更多信息:https://wiki.ubuntu.com/NotifyOSD#Bubble_appearance_and_layout
此外,您可以使用以下命令行发送自己的消息:

user@machine ~$ notify-send “Text of message”

只需更新由udev启动的脚本即可使用它。
为解决与以root身份运行notify-send命令相关的问题。
请尝试以普通用户身份运行它,例如:
su <YOURUSER> -c 'notify-send “Text of message”'

在脚本中运行notify-send命令将无法正常工作,因为它将被执行为sudo notify-send,这是主要的问题。我将尝试使用此服务名称,几分钟后会更新。 - Sxubach
好的,看来我实际上不知道该如何处理这个服务,你能给我一些指示吗?另外,我可以确认当以root身份运行notify-send时,它不会显示任何内容,这就是我所说的解决方法的全部意义。 - Sxubach
更新答案,提出解决“root”问题的建议。检查一下,如果有问题再回来。 - deimus
很高兴看到我并不那么迷茫,我已经尝试过这个了。现在我找到了这个人 http://unix.stackexchange.com/questions/116536/usb-connect-disconnect-notification,虽然他使用的是其他操作系统,但我还是试了一下 export DISPLAY=":0" 但它也没有起作用。 - Sxubach

2
notify-send() 
{
    local display=$DISPLAY
    local user=$(who | grep '('$display')' | awk '{print $1}')
    local uid=$(id -u $user)
    sudo -u $user DISPLAY=$display DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$uid/bus notify-send "$@"
}

在uos1022系统中,我可以通过环境变量$DISPLAY查询自己的窗口,从而成功地以root用户弹出通知栏。

1

我尝试了Fabio A的解决方案。然而,我注意到它在我的Arch Linux安装中并不一致地工作。问题是who没有显示tty1会话的端口号:

$ who
john       tty1         2021-03-21 09:02

我正在Arch上通过exec startx运行i3。另一方面,我注意到在Ubuntu桌面安装中,who的输出完全不同。 在这里,显示编号会显示:

$ who
john       :0           2021-03-21 09:49 (:0)

所以我在寻找另一种方法来摆脱who命令。我发现ps aux包含这个有用的条目,其中包含显示号码和用户名:

$ ps aux | grep xinit
john 785 763 0 19:14 tty1 S+ 0:00 xinit /home/john/.xinitrc -- /etc/X11/xinit/xserverrc :0 vt1 -keeptty -auth /tmp/serverauth.gGcqw2rJXG

这是我编写的新脚本:

#/bin/bash

xinit_pid=$(pgrep xinit)

if [ -n "xinit_pid" ]; then
    xinit_ps=$(ps --no-headers -f $xinit_pid | head -n 1)
    display=$(echo "$xinit_ps" | grep -Po " :[0-9]+ " | tr -d " ")
    user=$(echo "$xinit_ps" | cut -d " " -f 1)
    uid=$(id -u $user)
    echo "Display environment: $display $user $uid"
    sudo -u $user DISPLAY=$display DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$uid/bus notify-send "$@"
else
    echo "Warning: Could not find xinit process!"
fi

任何其他脚本都可以通过以下方式调用此脚本:

bash /opt/notify-send-helper Title Message -t 5000

顺便提一下:我使用的是dunstify而不是notify-senddunstify有一个优点,就是可以为通知分配ID:只显示相同ID的最新通知。

编辑:我曾经查询过进程“Xorg”。然而,奇怪的是,我注意到在一台机器上,这个进程是以root身份运行的。我改用了“xinit”进程,它的功能完全相同,但似乎总是由普通用户运行。


1

对于我来说,这种更简单的方法是有效的:

dbus-launch notify-send "Header" "Message"

0

最近我也在使用notify-send时遇到了一些困难,但最终成功解决了(在Ubuntu 16.04下)。

我认为有两个方面需要注意。首先,调用用户必须具有访问显示器的权限,其次需要指定要显示消息的显示器。

root@mymachine~# who
root     tty1         2017-06-19 16:30
<user1>  tty7         2017-06-20 07:15 (:0)
<user1>  pts/2        2017-06-20 07:42 (:0.0)
root     pts/14       2017-06-20 07:05 (<IP1>)
<user1>  pts/16       2017-06-20 07:15 (:0.0)
root     pts/17       2017-06-19 17:15 (<IP2>)
<user2>               2017-06-20 07:39 (<IP3>:2) #VNC
<user1>  pts/26       2017-06-19 18:03 (<IP3>:1.0) #VNC

对我有效的方法是

su - <user2> -c "DISPLAY=<IP3>:2 notify-send hi"

我认为通过切换用户,您使用他们的~/.Xauthority。授权后,指定显示器即可正常工作。

到目前为止,我使用了另一种方法来获取权限。我循环遍历每个已登录用户的~/.Xauthority文件,并收集他们的授权cookie。之后使用正确的DISPLAY变量即可正常工作。我甚至收集了显示管理器(在我的情况下是lightdm)的cookie。

~/.Xauthority文件(收集后):

root@mymaching:~# xauth list
<HOSTNAME3>:3  MIT-MAGIC-COOKIE-1  0ebdee59ee015f49066f372b00589420
<HOSTNAME3>:1  MIT-MAGIC-COOKIE-1  74254e326e8904419d005a05a6e95a8c
<HOSTNAME3>/unix:0  MIT-MAGIC-COOKIE-1  54d4cdb35eff20375e486f88e6ac8c74
<HOSTNAME3>:2  MIT-MAGIC-COOKIE-1  c6a07838c7456224799eedfff2be7cd5

目前我的脚本(我猜还不是最终版)

#!/bin/bash
users="$(who | awk '{print $1}' | sort -u | grep -v root)"
rm ~/.Xauthority
touch ~/.Xauthority
for user in $users; do
   xauth_file=/home/$user/.Xauthority
   while read cookie; do
      xauth add $cookie
   done <<< "$(xauth -f $xauth_file  list | grep $HOSTNAME)"
done
for xauth_file in $(find /var/run/lightdm -type f); do
   while read cookie; do
      xauth add $cookie
   done <<< "$(xauth -f $xauth_file  list | grep $HOSTNAME)"
done
for display in $(xauth list | awk '{print $1}' | cut -d/ -f2); do
   DISPLAY=$display notify-send "$@"
done

说明: <> 中的项目已被匿名。 IPX 与 HOSTNAMEX 匹配

您好, dasBaschdi


0

我也在研究如何修复重新启动时出现的背景损坏问题。我想添加一个脚本到 /etc/pm/sleep.d/ 来重置它,但需要设置 DBUS_SESSION_BUS_ADDRESS(gnome 桌面)。我发现存储在 /home/user/.dbus/session-bus/* 文件中的 DBUS_SESSION_BUS_ADDRESS 与用户环境中的不匹配。但我在其中一个 dbus-daemon 命令中找到了可用的地址。

因此,通过下面的代码片段,我成功地获取了 DBUS_SESSION_BUS_ADDRESS,并成功地使用了它。请将 "[username]" 替换为您的用户名。希望这可以帮助到您。

$ export DBUS_SESSION_BUS_ADDRESS=$(pgrep -a dbus-daemon -U [username] | grep -o 'unix:abstract.*$')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接