10

And don't say "$TERM" – it's always xterm.

How can a bash script tell what terminal it's running in, specifically whether it's iTerm, Terminal.app, or actually an xterm?

I ask because reset does not work¹ out of the box on Terminal.app and iTerm2. iTerm2, however, does recognize an escape sequence for doing a terminal reset (\x1b]50;ClearScrollback\x07), and if I could detect it, I could override reset with an alias that does the right thing. AFAICT, Terminal.app lacks a reset sequence, and people resort to ridiculous tom-hackery to hack around that.

My end goal here is to have reset work the same whether I'm working on OS X or Linux, working locally or remotely through SSH. (I don't want to have to try to remember which, and it's useful to do reset && command-that-outputs-a-bunch and have up-enter work.) Terminal.app and iTerm are throwing a wrench in this plan by not implementing reset correctly.

This means that simply overriding reset isn't quite it: if I'm on a Linux machine, it needs to know whether I'm using gnome-terminal or iTerm in order to send the right escape sequence.

Is there any way (even if I need an ioctl) to ask the terminal what it really is?

¹For the purposes of this question, reset should clear the screen, reset the cursor, and wipe the scrollback buffer.

6
  • Well, this is a feature, not a bug, or so they say. What happens if you open Terminal.app's settings, terminal tab and set scrollback lines to 0? Does that disable any and all text above the current line, or just anything above the top of the screen? I know, it's not exactly what you asked for, worth a shot.
    – nitro2k01
    Commented Dec 4, 2013 at 18:30
  • @nitro2k01: I'm not sure what that would accomplish? I want scrollback. I just want to be able to clear it now and then, preferably with reset, since that's what my fingers know.
    – Thanatos
    Commented Dec 4, 2013 at 19:09
  • As for your “reset” issue: to clarify, you’re expecting the reset command to clear the terminal emulator’s scroll-back content, but that’s not guaranteed to do that, because scroll-back is a terminal emulator-specific feature, not really a part of a terminal. However, Terminal supports an extension of the ED (Erase in Display) escape sequence to erase the scroll-back ESC [ 3 J. You can clear the screen, then use that, e.g., reset && printf '\e[3J’
    – Chris Page
    Commented Dec 8, 2013 at 15:06
  • See my answer here apple.stackexchange.com/a/113168/6883 for more details about the Erase in Display extension.
    – Chris Page
    Commented Dec 8, 2013 at 15:43
  • @ChrisPage: I realize that terminals are quirky things, but if you declare yourself to be an xterm (through TERM=xterm) I'd expect that you emulate a superset of the XTerm, which clears its scrollback on reset. (Just as if you sent the escape sequence for "blue", you'd expect blue.) Granted, my xterm tells me that Erase is backspace., which I'm thankful nothing else does; that's just annoying.
    – Thanatos
    Commented Mar 7, 2014 at 0:16

3 Answers 3

12

Use $TERM_PROGRAM.

iTerm sets it to iTerm.app, and Terminal.app to Apple_Terminal.

5
  • Heh, OK, this is clearly better than my hack, +1 :). The hack should work for any terminal emulator though, not just those two.
    – terdon
    Commented Dec 4, 2013 at 18:57
  • There is no single way to detect every terminal emulator. For xterm, you can check for the $XTERM_VERSION variable, for example. That will take care of what are probably the three most popular emulators on OS X.
    – Chris Page
    Commented Dec 8, 2013 at 14:59
  • Accepting this, as it's a good start. Unfortunately, it's not quite this easy, as this variable isn't available inside an SSH session. I suspect there are configs that I can edit to forward it.
    – Thanatos
    Commented Mar 5, 2014 at 23:50
  • 2
    @Thanatos sshd_config's AcceptEnv probably. As this (your shell runs on a different host than the one your Terminal runs on) is very important information, it really should be part of the question.
    – Daniel Beck
    Commented Mar 6, 2014 at 10:04
  • @DanielBeck: It's not strictly the case; I'd like to to do the same locally and remotely. What I'm going for is that typing "reset" into a terminal causes a reset of the terminal, no matter whether I'm on OS X or Linux, working locally or remote. I've edited this into the question.
    – Thanatos
    Commented Mar 7, 2014 at 0:07
2

$TERM has nothing at all to do with the terminal emulator currently running, it is just your default terminal and can be set to anything at all. To get the name of the terminal emulator you are running, you can use ps to get the PID of the parent process of your current shell.

NOTE: The following will fail on OSX but should work OK on Linux

The PID of your current shell process is $$. From there, you can use ps to show a process tree, and print the PID of the parent of your current shell session:

ps -axjf | awk -v pid=$$ '($2==pid){print $1}'

You can then pass that PID to ps and tell it to print the command name:

ps -o comm=  $(ps -axjf | awk -v pid=$$ '($2==pid){print $1}')

That will truncate the name, it should be enough for you to figure it out but might not be good for scripting. To get the complete name, you could try

ps --no-headers $(ps -axjf | awk -v pid=$$ '($2==pid){print $1}') | awk '{print $NF}'

This is what I get on my system using a few different terminals:

  1. terminator

    $ ps --no-headers $(ps -axjf | awk -v pid=$$ '($2==pid){print $1}') | 
       awk '{print $NF}'
    /usr/bin/x-terminal-emulator
    
  2. gnome-terminal

    $ ps --no-headers $(ps -axjf | awk -v pid=$$ '($2==pid){print $1}') | 
       awk '{print $NF}'
    /usr/lib/gnome-terminal/gnome-terminal-server
    
  3. xterm

    $ ps --no-headers $(ps axjf | awk -v pid=$$ '($2==pid){print $1}') | 
       awk '{print $NF}'
    xterm
    
9
  • Doesn't work on OS X: ps: illegal option -- f
    – Daniel Beck
    Commented Dec 4, 2013 at 18:51
  • @DanielBeck darn BSD style, thanks. Could you try again with the updated version? Adding a - before the options should work according to OSX's man ps.
    – terdon
    Commented Dec 4, 2013 at 18:56
  • Better, but still not working. Output format is different (PID is $2, PPID is $3), and the parent process of the shell might be login (depending on Terminal config), with different params. However, its parent process is Terminal. --no-headers doesn't exist, you'd need something like tail -n1. And since all processes with UI have an argument -psn_0_..., awk '{print $NF}' doesn't work either.
    – Daniel Beck
    Commented Dec 4, 2013 at 19:26
  • @DanielBeck well shucks then. OK, thanks I'll make it clear that this fails on OSX.
    – terdon
    Commented Dec 4, 2013 at 19:32
  • Note that this only works locally. You can’t use this approach to figure out what terminal emulator is being used on a remote client. The best answer is to look for variables like $TERM_PROGRAM (as mentioned in @DanielBeck’s answer) and $XTERM_VERSION to deduce the emulator application.
    – Chris Page
    Commented Dec 8, 2013 at 15:45
1

Here's a portable way to get the name or path of the parent process:

iTerm 2:

$ ps -p $(ps -p $$ -o ppid=) -o comm=
/Applications/iTerm.app/Contents/MacOS/iTerm

gnome-terminal in Ubuntu:

$ ps -p $(ps -p $$ -o ppid=) -o comm=
gnome-terminal

Terminal.app:

$ ps -p $(ps -p $$ -o ppid=) -o comm=
login

Note that if Terminal.app is set to open new shells with the default login shell, the parent process of the shell is login and not the terminal.

The comm column is the full path of the command in OS X and the command name truncated to 15 characters in the procps implementation in Linux.

1
  • Tried in iTerm and got login -- Did I customize my profile some time back to run the command login -fp danielbeck?
    – Daniel Beck
    Commented Dec 8, 2013 at 15:34

You must log in to answer this question.

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