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 ingnome-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 threegnome-terminal
windows, and twoxterm
windows.
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.