Bash: How to determine whether terminal is opened by third-party app

You could probably do it by walking back up the ancestry of the shell and working out whether it was started by something that equates to "you", or another program.

Get the shell's PID (process ID), and from that its PPID (parent process ID). Keep going up until you get to something which tells you where it came from. You may need to experiment on your system -- at least, I don't know whether it'll be universal.

For example, on my system, get the PID of a shell and use ps to show that it's bash:

$ echo $$
18852
$ ps --pid 18852
  PID TTY          TIME CMD
18852 pts/1    00:00:00 bash

Get the PPID of 18852:

$ ps -o ppid= -p 18852
18842

Find out what the PPID (18842) is:

$ ps --pid 18842
  PID TTY          TIME CMD
18842 ?        00:00:02 gnome-terminal

We can see it's gnome-terminal, i.e. the terminal emulator / terminal window. Maybe that's good enough for you, if your shell launched by the other program is not running in a terminal emulator window.

If it's not good enough, go up another level:

$ ps -o ppid= -p 18842
 2313
$ ps --pid 2313
  PID TTY          TIME CMD
 2313 ?        00:00:00 init

This tells us that gnome-terminal was started by init. I suspect your shell started by another program will have something different there.


As far as Visual Studio Code goes, there apparently is a way to set additional environment variables for the integrated terminal. So, set up Visual Studio to use this config:

"terminal.integrated.env.linux": {
  "visual_studio": "true"
}

And within ~/.bashrc:

if [ -n "$visual_studio" ]; then
    # do something for Visual Studio
else
    # do something else for other types of terminal
fi

In general, you could rely on the environment given to the bash process. For instance, the $TERM variable, and run a similar if..then...else...fi branch for [ "$TERM" = "xterm" ] or something else. On case-to-case basis, you can investigate the differences in the environment via running env in each console, save that to file as in env > output_console1.txt, and diff output_console1.txt output_console2.txt as suggested by dessert in the comments.


If you're talking about one specific third-party app, then use an environment variable. Most programs will pass along the entire environment unchanged when they fork+exec new processes.

So, start this app with a custom env var you can check for. e.g. make an alias for it like alias vs=RUNNING_FROM_VSCODE=1 VSCode, or make a wrapper script like this:

#!/bin/sh
export RUNNING_FROM_VSCODE=1
exec VSCode "$@"

Then in your .bashrc, you can do

if (($RUNNING_FROM_VSCODE)); then
   echo "started from inside VSCode"
   # RUNNING_FROM_VSCODE=0  # optional if you only want the immediate child
fi

A bash arithmetic statement (( )) is true if the expression evaluates to a non-zero integer (which is why I used 1 above). The empty string (for an unset env var) is false. It's nice for bash boolean variables, but you could just as easily use true and check for it with a traditional POSIX

if [ "x$RUNNING_FROM_VSCODE" = "xtrue" ]; then
   echo "started from inside VSCode"
fi

If your app mostly clears the environment for its children, but still passes on $PATH unchanged, you could use this in your wrapper:

#!/bin/sh
export PATH="$PATH:/dev/null/RUNNING_FROM_VSCODE"
exec VSCode "$@"

and check for it with a pattern-match like bash [[ "${PATH%RUNNING_FROM_VSCODE}" != "$PATH" ]] to check if stripping a suffix from PATH changes it.

This should harmlessly do one extra directory lookup when the program is looking for not-found external commands. /dev/null is definitely not a directory on any system, so it's safe to use as a bogus directory that will quickly result in ENOTDIR if PATH searches don't find what they're looking for in earlier PATH entries.


Here's my 2 cents. Just add it to your .bashrc. Replace terminals with your favorite terminals and export command with yours.

run_in_terminal(){
  local parent_command="$(ps --no-headers --pid $PPID -o command | awk '{print $1;}')"
  local parent="$(basename $parent_command)"
  local terminals=( gnome-terminal st xterm ) # list your favorite terminal here
  if [[ ${terminals[*]} =~ ${parent} ]]; then
    # Your commands to run if in terminal
    export MY_VAR_IN_TERMINAL="test"
  fi
}
run_in_terminal