5

I have used pstree to find the name of the parent emulator of running shell script using something similar to the following:

pstree -s $PPID | awk -F '---' '{print $6}'

This works in my current system. I tested in mate-terminal and xterm but not sure if this will work on other Linux systems/platforms and other terminals. Is there a better/tidier (more portable way) way of achieving this?

5
  • 2
  • Do you, by "terminal", mean the terminal emulator (xterm, rxvt etc.) or the terminal device (/dev/pts/23, /dev/ttyp3 etc.)?
    – Kusalananda
    Feb 19, 2016 at 12:33
  • Emulator I mean.
    – coffeMug
    Feb 19, 2016 at 12:34
  • User: jdewolf published this code as answer to a duplicate of this question: ps -p $(ps -h -o ppid -p $$) -o cmd. Nov 15, 2017 at 13:52
  • You really can't assume there will be a terminal emulator running a script. For example it could be an ssh session from a different machine, or even someone logged on to one of the non-graphic ttys.
    – roaima
    Sep 7, 2020 at 17:31

3 Answers 3

8
ps -o comm= -p "$(($(ps -o ppid= -p "$(($(ps -o sid= -p "$$")))")))"

May give you good results. It gives the name of the process that is the parent of the session leader. For processes started within a terminal emulator, that would generally be the process running that terminal emulator (unless things like screen, expect, tmux... are being used (though note that screen and tmux are terminal emulators), or new sessions are started explicitly with setsid, start-stop-daemon...)

Or breaking it down into individual steps using variables (which can also help make the script more self explanatory):

sid=$(ps -o sid= -p "$$")
sid_as_integer=$((sid)) # strips blanks if any
session_leader_parent=$(ps -o ppid= -p "$sid_as_integer")
session_leader_parent_as_integer=$((session_leader_parent))
emulator=$(ps -o comm= -p "$session_leader_parent_as_integer")

The stripping of whitespace around numbers here is done using $((...)) arithmetic expansion. You could also doing it using the split+glob operator (assuming an unmodified $IFS) or as suggested by @ack in comments using xargs:

ps -o sid= -p "$$" |
  xargs ps -o ppid= -p |
  xargs ps -o comm= -p

You could also try parsing wtmp where terminal emulators usually log an entry with their pid associated with the pseudo-terminal device. This works for me on a Debian system provided expect/screen/tmux... are not involved:

ps -o comm= -p "$(
  dump-utmp -r /var/log/wtmp |
  awk -v tty="$(ps -o tty= -p "$$")" -F ' *\\| *' '
    $2 == tty {print $5;exit}')"

(using dump-utmp from GNU acct).

2
  • 1
    While the first implementation looks kinda Lispy (and don't get me wrong, I like Lisp a lot!) and the second expanded one looks more like Lisp doing Warp 9, Bash isn't such a great Lisp. The other implementations are IMHO much more complicated than they need to be. There is a much simpler, straightforward, down to Earth way of doing it, using just plain old pipes: $ ps -o sid= -p "$$" | xargs ps -o ppid= -p | xargs ps -o comm= -p
    – ack
    Jan 23 at 6:15
  • @ack, very good point, I've added it in. Jan 23 at 11:14
1

To find the name of the terminal emulator used by the current shell, you could ask the X window system to give you the name of the window that the shell is currently visible in:

$ xwininfo -id $WINDOWID | awk '/^xwin/ { print $NF }'

This gives back the string "xterm" for me in XTerm, and "urxvt" when I run in Rxvt-unicode. The result will probably be different if you have the habit of changing the window title though, because that's what is being handed back to you here I think.

10
  • What if xwininfo is not available?
    – coffeMug
    Feb 19, 2016 at 13:02
  • Well, what if pstree is not available or if it's incompatible with your original solution? (The -s flag on OpenBSD systems, for example, have different semantics).
    – Kusalananda
    Feb 19, 2016 at 13:04
  • That is exactly the reason I was looking for something more portable!
    – coffeMug
    Feb 19, 2016 at 13:07
  • 2
    That gives you the window's title which can be overridden at run time or in configuration, you could use eval "$(xprop -notype -id "$WINDOWID" 32i '=$0' _NET_WM_PID)"; ps -o comm= -p "$_NET_WM_PID" to get the process name instead. Feb 19, 2016 at 13:15
  • 2
    @cofferMug, xwininfo is a standard X command like xprop. If your system has X11 terminal emulators, it should have those commands. Feb 19, 2016 at 13:16
0

Building on stephane-chazelas solution to make it work under tmux (i.e. return the terminal emulator that the tmux client is using for display), this seems to work for me:

TERMINAL_EMULATOR="$(ps --pid $(ps --pid $$ -o ppid=) -o comm=)"
if [[ "${TERMINAL_EMULATOR}" =~ tmux ]]; then
    export TERMINAL_EMULATOR=$(ps --pid "$(($(ps --pid $(ps --pid $(tmux display-message -p "#{client_pid}") -o sid=) -o ppid=)))" -o comm=)
else
    export TERMINAL_EMULATOR
fi

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.