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