Bash:如何判断终端是否由第三方应用打开

Bash:如何判断终端是否由第三方应用打开

我希望我的 bash 脚本(特别是我的~/.bashrc)仅在我直接打开终端时执行某些操作,如果通过应用程序(例如 VS Code)打开终端,则执行其他操作。我如何确定情况如何?有变量吗?提前致谢。

答案1

您可以通过追溯 shell 的祖先并查明它是否是由相当于“您”的东西或另一个程序启动的来做到这一点。

获取 shell 的 PID(进程 ID),然后获取其 PPID(父进程 ID)。继续向上查找,直到找到可以告诉您它来自哪里的某个东西。您可能需要在您的系统上进行实验 —— 至少,我不知道它是否通用。

例如,在我的系统上,获取 shell 的 PID 并使用ps它来显示它bash

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

获取 18852 的 PPID:

$ ps -o ppid= -p 18852
18842

找出 PPID(18842)是什么:

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

我们可以看到它是 gnome-terminal,即终端仿真器/终端窗口。如果您由其他程序启动的 shell 未在终端仿真器窗口中运行,那么这对您来说可能已经足够了。

如果还不够好,请再上升一个级别:

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

这告诉我们是gnome-terminal由 启动的init。我怀疑由另一个程序启动的 shell 会有所不同。

答案2

就 Visual Studio Code 而言,显然有一种方法可以设置集成终端的附加环境变量。因此,设置 Visual Studio 以使用此配置:

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

并且在~/.bashrc

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

通常,你可以依赖为进程提供的环境bash。例如,变量$TERM,并运行类似的if..then...else...fi分支[ "$TERM" = "xterm" ]或其他内容。根据具体情况,您可以通过env在每个控制台中运行来调查环境中的差异,将其保存为文件,如env > output_console1.txt,并diff output_console1.txt output_console2.txt按照建议的那样评论中的甜点

答案3

如果您谈论的是某个特定的第三方应用程序,那么请使用环境变量。大多数程序在 fork+exec 新进程时都会传递整个环境而不做任何更改。

所以,使用您可以检查的自定义环境变量启动此应用程序. 例如为其创建一个别名alias vs=RUNNING_FROM_VSCODE=1 VSCode,或者创建一个包装脚本,如下所示:

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

然后在你的.bashrc,你可以做

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

(( ))如果表达式求值为非零整数,则bash 算术语句为真(这就是我上面使用的原因)。空字符串(对于未设置的环境变量)为假。这对于 bash 布尔变量来说很不错,但您也可以使用传统的 POSIX1轻松使用和检查它true

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

如果你的应用主要清除其子应用的环境,但仍然保持$PATH不变,您可以在包装器中使用它:

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

并使用像 bash 这样的模式匹配来检查它,[[ "${PATH%RUNNING_FROM_VSCODE}" != "$PATH" ]]以检查从 PATH 中删除后缀是否会改变它。

当程序正在寻找未找到的外部命令时,这应该无害地进行一次额外的目录查找。 /dev/null绝对不是任何系统上的目录,因此可以安全地用作虚假目录,ENOTDIR如果 PATH 搜索在早期 PATH 条目中找不到他们要寻找的内容,则会很快导致出现此错误。

答案4

这是我的意见。只需将其添加到您的.bashrcterminals用您最喜欢的终端和export命令替换。

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

相关内容