How to detect the number of opened terminals by the user

I am using Ubuntu and can manually change the bash shell prompt color to green using

export PS1="\e[0;32m[\u@\h \W]\$ \e[m" 

However, I want the shell prompt color to automatically change whenever I open a new terminal or tab. I am aware that the basic tty TERM has 16 colors, and it's okay to rotate the colors if more than 16 terminals are open. Will the solution also work when I connect through Putty, tmux or screen.

My idea is to write a shell script and place it in .bashrc which detects the new terminal session the user has opened and increment a global counter from \e[0;31m[ to \e[0;47m[. How to detect the number of opened terminals by the user?


Solution 1:

If you really need to get the number of terminal you have open, go for counting the files owned by you under /dev/pts (although this might include ones opened by background processes, not by graphical terminal emulators). Alternatively, count the number of child processes of your terminal emulator(s), as shown by Jacob in the first line of his response.

Avoid relying on who's output, and looking for gnome-pty-helper processes, since these don't work in newer gnome-terminal versions.

Note that nowadays pretty much all graphical terminal emulators (including putty) and multiplexers (screen, tmux) support 256 colors. You can get really nice colored prompts if you use this palette.

My recommendation for a very simple solution is to base the color on the current tty line's number. E.g. process the output of the tty command to take the number only and derive the color from that. A certain tty line number is only given to one terminal at a time, you'd have to close that terminal first before the same line number is reissued by the kernel. This, combined with 256 colors, automatically guarantees that you won't see the same color twice at a given time (and even with 16 colors it'd give a quite even distribution). No need for maintaining a global counter, and no need for counting terminals or processes.

Solution 2:

In a single user situation, if we take the example of xterm, we can simply count the number of pids of xterm; xterm creates a separate pid for each and every window.
gnome-terminal however runs a single pid, but the good news is that it creates a child process for each and every window and/or tab. we can retrieve these child processes by the command:

pgrep -P <pid_of_gnome-terminal>

There are however a few complications to deal with:

  • Reading your question, we may assume, that user in this case is actually owner of the x-session. Usually we can simply use the $USER -variable, but this might not match the currently logged in user of $DISPLAY.

  • In a multi-user situation, pids belonging to the (either which) terminal application, do not necessarily belong to the current $DISPLAY. We need to split off only the relevant pids and child-pids.

  • On Unity (15.10 or lower), if a second user logs in, an additional process is started (gnome-pty-helper), which appears as a child process in gnome-terminal, but the process (obviously) has no window or tab. On Mate, the process exists anyway.

In short

To count the number of tabs and/or windows of a terminal application, we need to:

  • See if we run a terminal application which has multiple pids or a single pid on one $DISPLAY (x-session)
  • From the running processes, split off only the relevant pids, running on this $DISPLAY
  • If the application runs child-processes for its pid (for windows/tabs), see if gnome-pty-helper runs, to correct the number.

This can very well be scripted however, to reliably find the number of currently opened windows and/or tabs.

The script

In the script below, the targeted terminal application is used as an argument. The script works on many terminals I tested it on. An exception is Tilda at this moment.

An example

  • I have two users logged in, one (not the current) with two gnome-terminal windows, one (the one in the image) with three gnome-terminal windows, and two xterm windows.

enter image description here

The command:

/path/to/get_terms.sh gnome-terminal

outputs:

3

while

/path/to/get_terms.sh xterm

outputs:

2

The script

#!/bin/bash

terminal=$1

# get the user running the current x-session
username=$(who | grep $DISPLAY | head -1 | awk '{print $1}')
# get the pid of the terminal for the current user
userpid=$(pgrep -u $username $terminal)
# check what type the terminal is (multi pid/single pid)
npids="$(echo "$userpid" | wc -w)"
# in case of a single pid, count the children
if [ "$npids" -eq 1 ]; then
  # check if gnome-pty-helper runs (starts when multiple users are logged in)
  ptpid=$(pgrep gnome-pty-helpe)
  # get number of child- procs
  let "orig = $( pgrep -P $(pgrep -u $username $terminal) | wc -w )" 
  # if pty-helper runs, correct the number of child procs
  if [ -n "$ptpid" ] && [ -n "$userpid" ]; then
    let "n_terms = $orig-1"; else let "n_terms = $orig"
  fi
  # if no child procs run, n-terminals = n-counted pids (difference Mate <> Unity)
  if [ "$n_terms" -eq 0 ]; then echo $orig; else echo $n_terms; fi
# in case of multiple pids, count the pids
elif [ "$npids" -gt 1 ]; then echo $npids
fi

To use

  • Copy the script into an empty file, save it as get_terms.sh, make it executable and run it by the command:

    /path/to/get_terms.sh <terminal_application>
    

Solution 3:

An awk way:

who | awk 'BEGIN{count=0}{ if(NR!=1){count++} }END{print count}'

Explanation:

In above 1 liner command, awk is used to find the count of terminal. Inside awk program, it is just checking the number of lines return by who command - 1.