![Bash:如何判断终端是否由第三方应用打开](https://linux22.com/image/1064098/Bash%EF%BC%9A%E5%A6%82%E4%BD%95%E5%88%A4%E6%96%AD%E7%BB%88%E7%AB%AF%E6%98%AF%E5%90%A6%E7%94%B1%E7%AC%AC%E4%B8%89%E6%96%B9%E5%BA%94%E7%94%A8%E6%89%93%E5%BC%80.png)
我希望我的 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
这是我的意见。只需将其添加到您的.bashrc
。terminals
用您最喜欢的终端和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