I'm implementing USB plug/unplug notification (here's related question), and I need to execute something like notify-send "device plugged" "My Device Title". The problem is that to make this command work, I should firstly set DISPLAY, like this:

export DISPLAY=":0.0"

And secondly, this command should be called by appropriate user. Say, for user dimon:

su dimon -c "notify-send 'device plugged' 'My Device Title'"

So, I need to get the list of all active X sessions and appropriate users, and call notify-send for each user on his DISPLAY.

I tried to use w for that, example output at Linux Mint 13 MATE:

USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU WHAT
dimon    tty8     :0               Sun15    3days  1:38m  1.95s x-session-manager
dimon    pts/0    :0               Sun15    0.00s  0.20s  0.00s tmux

So we have both username and display. I decided to parse it like that:

declare -a logged_users=(`w |grep -vP "^(USER| )" |awk '{if (NF==8){print $1" "$3} else {print $1" :0"}}' |sort |uniq`)

Now, I have array logged_users: [0] contains dimon, and [1] contains :0. This would be great, but unfortunately it works not everywhere. Say, on Ubuntu 12.04 with lightdm we have this w output:

USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU WHAT
nui      tty7                      18:22   35:56   1.66s  0.11s gnome-session -
nui      pts/0    :0.0             18:55    5.00s  0.20s  0.00s w

No idea why there's no FROM value for gnome-session. And even worse one, at xubuntu:

USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU WHAT
nui      tty7                      15:50   31:07  52.55s  0.13s /bin/sh /etc/xd

No display at all! If other user is logged in, no display is specified for him too (but actually it's :1.0)

So, I'm looking for another approach. I also know we have a list of all active X sessions here: /tmp/.X11-unix , and I can get the list of them like this:

cd /tmp/.X11-unix && for x in X*; do echo ":${x#X}"; done

But then, I don't know how to retrieve users.

So, how to get the list of all active X sessions and appropriate users?

2 Answers 2


This is a solution for the users of local X servers (ignoring local X clients with remote or virtual X servers).

You determine the PID of the display manager (which is the parent PID of Xorg), determine the PIDs of its children and determine the user of all processes which have one of them as parent:

#! /bin/bash
xorg_pid=$(pidof -s /usr/bin/Xorg)
test -n "$xorg_pid" || exit 1
dm_pid=$(ps -eo pid,ppid,args | \
    awk -v xorg_pid=$xorg_pid '$1 == xorg_pid {print $2}')
pid_list="$(ps -eo pid,ppid,cmd | \
    awk -v dm_pid=$dm_pid '$2 == dm_pid {if (matchnr == 0) '\
'{ printf "%s%d ","$2 == ",$1; matchnr++;} '\
'else printf "%s%d ","|| $2 == ",$1;}')"
ps -eo pid,ppid,user,cmd | awk "$pid_list"'{print $3}'
  • What if you used pgrep Xorg instead. I have 2 running now so how would this handle multiples?
    – slm
    Feb 26, 2014 at 19:08
  • @slm You don't happen to have tried the code...? Feb 26, 2014 at 19:10
  • Of course I did. I'm seeing that it only finds one.
    – slm
    Feb 26, 2014 at 19:10
  • @slm That's the intention. All instances have the same parent (at least that is the assumption of my script) thus using the first hit only is enough. I have two Xorg instances running, too. Would be difficult to test such code otherwise... Feb 26, 2014 at 19:13
  • Maybe I'm confused, doesn't he want to see all the usernames that are running X?
    – slm
    Feb 26, 2014 at 19:22

I had the same notify-send problem.

This method (also posted here) uses the environment information which ps e provides. ps e -u username | sed -rn 's/.* DISPLAY=(:[0-9]*).*/\1/p' outputs a list of all the DISPLAY numbers in the environments of all user username's processes.

If there is a root-owned window on your desktop then root will also have some processes with the same DISPLAY number, but otherwise one DISPLAY should only be associated with one user. (Not the other way round - right now I'm logged in at two tty's with two X sessions, so I am using both :0 and :1.)

This code will output all the currently used DISPLAYs (hence all the X sessions) of all the currently logged-in users. (root is skipped)

Note the sudo on the ps command: root permissions are needed to view the environments of other users' processes. Of course if the script is run by root it's unnecessary.

Usernames and display numbers are used as the indices of associative arrays to keep only unique values.


declare -A disps usrs

for i in $(users);do
    [[ $i = root ]] && continue # skip root
done # unique names

for u in "${!usrs[@]}"; do
    for i in $(sudo ps e -u "$u" | sed -rn 's/.* DISPLAY=(:[0-9]*).*/\1/p');do

for d in "${!disps[@]}";do
    echo "User: ${disps[$d]}, Display: $d"
    #sudo -u "${disps[$d]}" DISPLAY="$d" notify-send "Title" "Message"

The final commented-out line shows how notify-send could be called.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .