6

How can I get the PID of the GNOME Terminal instance I'm using from within a Bash script?

I can run xprop _NET_WM_PID and then manually click the terminal window, but I'd like to completely automate this.

ændrük
  • 76,794

3 Answers3

4

I've written two recursive functions that trace parents of a process

get_parent()
{
 ps --no-headers -p $1 -o ppid,cmd 
}

process_list()
{
  if [ "$1" -ne "1"  ]; then
   PARENT="$(get_parent $1 )"
   printf "%s\n" "$PARENT"
   process_list $( printf "%s" "$PARENT" | awk '{print $1}'  )
  fi 
}

print_header()
{
  printf "PPID\tPROCESS\n"
  for i in $(seq 1 20 ) 
  do
     printf "-"
  done
  printf "\n"
}
print_header
process_list $$

What I've found in the process is this:

$ bash get_process_list                                                        
PPID    PROCESS
--------------------
31264 bash get_process_list
31251 mksh
16696 gnome-terminal
15565 /bin/mksh
 2164 x-terminal-emulator
 1677 init --user
 1342 lightdm --session-child 12 19
    1 lightdm

So we could use the two functions and grep the gnome-terminal, assuming that's what the user wants. If the user wants any terminal emulator, that may be problematic because aside from checking lsof for a pts device open, there's no way to tell whether or not the process is a terminal emulator.

Aside from that , there is something very interesting as well:

$ bash get_process_list                                                                    
PPID    PROCESS
--------------------
32360 bash get_process_list
23728 -mksh
 2164 tmux
 1677 init --user
 1342 lightdm --session-child 12 19
    1 lightdm

tmux apparently forks itself and the process gets picked up by init , so again there's the obstacle.

Using Unity's Ayatana

The code bellow uses qdbus and Ayatana's dbus interface to list all gnome-terminal windows and whether they are focused at the moment or not. This can be later parsed or edited to output only active/focused window PID

Sample run:

$ bash get_gt_pd.sh                                                                    
XID:33554486    PID:20163   ACTIVE:true
XID:33554444    PID:20163   ACTIVE:false

And the code itself

get_gt_xid()
{ # Prints XID of each gnome-terminal window
 qdbus --literal org.ayatana.bamf \
      /org/ayatana/bamf/matcher \
     org.ayatana.bamf.matcher.XidsForApplication \
    /usr/share/applications/gnome-terminal.desktop
}

for window in  $(get_gt_xid | awk -F'{' '{ gsub(/\,|}|]/," ");print $2  }' )
do
  PID=$(qdbus org.ayatana.bamf /org/ayatana/bamf/window/"$window"\
        org.ayatana.bamf.window.GetPid)
  ACTIVE=$( qdbus org.ayatana.bamf /org/ayatana/bamf/window/"$window"\
            org.ayatana.bamf.view.IsActive  )
  printf "XID:%s\tPID:%s\tACTIVE:%s\n" "$window" "$PID" "$ACTIVE"
done
Sergiy Kolodyazhnyy
  • 105,154
  • 20
  • 279
  • 497
  • This returns the PID of my tmux instance. – ændrük Apr 06 '16 at 21:27
  • That wasn't mentioned in the question :) Of course if you have tmux run the script , the parent PID will be of tmux . What's your complete setup ? – Sergiy Kolodyazhnyy Apr 06 '16 at 21:36
  • Arbitrary—the answer should avoid making assumptions about my setup, where practical. – ændrük Apr 07 '16 at 20:41
  • @ændrük well , what sort of assumtions can we make ? can we at least assume that script will be run through gnome-terminal at all times ? Because if your ultimate goal is determining whether or not a script is being run over which terminal emulator, then it will be very difficult to determine - there's tons of terminal emulators, and searching for every possible string that is name of a terminal will be a bit difficult. To the os, terminal emulator is nothing but another process , distinguished from others only by pid – Sergiy Kolodyazhnyy Apr 07 '16 at 23:05
  • I shouldn't have distracted you by mentioning tmux. Consider instead that if I had used this answer from within a script I would have initially responded with "this returns the PID of my Bash instance." – ændrük Apr 07 '16 at 23:14
  • @ændrük still my question remains - can we assume gnome-terminal is what you're after or are you after any terminal emulator ? – Sergiy Kolodyazhnyy Apr 07 '16 at 23:22
  • @ændrük oh, by the way, tmux has a peculiar way of starting up where it forks and the new process gets picked up by init (which is what I've found with the two recursive functions I've written just now ), so . . .I don't think we'll be able to trace that :) eh, what the heck, might as well post my two functions – Sergiy Kolodyazhnyy Apr 07 '16 at 23:34
  • Yeah, using tmux makes this a much more difficult question. I should have used screen to illustrate my point instead. – ændrük Apr 07 '16 at 23:38
  • @ændrük I get your point, the shell will list its parent as screen or tmux, but then like it shows up in the output, tmux will be reported as having init as parent, not a terminal emulator – Sergiy Kolodyazhnyy Apr 07 '16 at 23:55
  • @ændrük by the way, screen works pefrectly fine - with my recursive approach i can find the gnome-terminal in the lineage. Maybe we should change the approach - find out the children of each gnome-terminal instance, and see if the script is among them – Sergiy Kolodyazhnyy Apr 07 '16 at 23:59
  • @ændrük I've made a small edit to my answer, let me know if that's closer to what you want. The small caveat is that the instance of gnome-terminal must be focused one – Sergiy Kolodyazhnyy Apr 24 '16 at 03:10
  • I like both of these interpretations of active or using — an ancestor process, or the active window. There's probably a simpler way of finding the ancestor, but I'll award this answer the check mark since it considers both interpretations. – ændrük Apr 27 '16 at 22:58
1

There are times when more than one instance is running — when I have a terminal open in a guest session, for example

The variable $PPID will give you the parent process for the current bash shell, which is often gnome-terminal.

To be safe though, the following will find the parent gnome-terminal process even if multiple bash shells are nested:

pstree -p -s $PPID | grep -Po 'gnome-terminal\(\K.*?(?=\))'


The following universal version will work for any shell, even if other grep instances are running. Deciphering it is left as an exercise for the reader ;)

pstree -p -a -s \
$(pstree -p -a | grep -B3 $RANDOM$RANDOM \
| grep -m1 `echo $SHELL |cut -d/ -f3` | cut -d, -f2)\
| grep gnome-terminal | cut -d, -f2
ish
  • 139,926
  • True, but I think any method that assumes there is only one GNOME Terminal instance is still fundamentally flawed. Another counterexample: gnome-terminal --disable-factory – ændrük May 20 '12 at 01:02
  • See edited answer ;) – ish May 20 '12 at 02:28
1

This solution feels the most robust to me. It recursively looks up the parent PID until finding one that belongs to GNOME Terminal.

find-parent() {
    i=($(ps -o pid= -o ppid= -o cmd= -p $1))
    ((i[0] == 1)) && return 1
    if [[ ${i[2]} =~ (^|/)gnome-terminal$ ]]; then echo ${i[0]}; else find-parent ${i[1]}; fi
}; find-parent $PPID
ændrük
  • 76,794