不要说“ $TERM
”——总是xterm
。
脚本如何bash
知道它在哪个终端运行,具体是 iTerm、Terminal.app 还是实际上是 xterm?
我之所以问这个问题,是因为reset
Terminal.app 和 iTerm2 上开箱即用¹。但是,iTerm2 可以识别执行终端重置的转义序列 ( \x1b]50;ClearScrollback\x07
),如果我能检测到它,我就可以reset
用执行正确操作的别名覆盖它。据我所知,Terminal.app 缺少重置序列,并且人们采取荒谬的黑客手段来解决这个问题。
我的最终目标是,reset
无论我在 OS X 还是 Linux 上工作,无论是本地工作还是通过 SSH 远程工作,都能获得相同的工作效果。(我不想费力记住哪个,而且这样做reset && command-that-outputs-a-bunch
并进行输入工作很有用。)Terminal.app 和 iTerm 未能正确实施,从而破坏了这一计划reset
。
这意味着简单的覆盖reset
是不够的:如果我在 Linux 机器上,它需要知道我是否正在使用gnome-terminal
iTerm 才能发送正确的转义序列。
有什么办法(即使我需要ioctl
)来询问终端它是什么真的是?
¹就这个问题而言,重置应该清除屏幕,重置光标,并擦除回滚缓冲区。
答案1
使用$TERM_PROGRAM
。
iTerm 将其设置为iTerm.app
,并将 Terminal.app 设置为Apple_Terminal
。
答案2
$TERM
与当前正在运行的终端仿真器完全无关,它只是您的默认终端,可以设置为任何值。要获取您正在运行的终端仿真器的名称,您可以使用ps
获取当前 shell 的父进程的 PID。
注意:以下操作在 OSX 上会失败,但在 Linux 上应该可以正常运行
当前 shell 进程的 PID 是$$
。从那里,您可以使用ps
显示进程树,并打印当前 shell 会话的父进程的 PID:
ps -axjf | awk -v pid=$$ '($2==pid){print $1}'
然后您可以将该 PID 传递给ps
并告诉它打印命令名称:
ps -o comm= $(ps -axjf | awk -v pid=$$ '($2==pid){print $1}')
这将截断名称,这应该足以让您弄清楚,但可能不适合编写脚本。要获取完整名称,您可以尝试
ps --no-headers $(ps -axjf | awk -v pid=$$ '($2==pid){print $1}') | awk '{print $NF}'
这是我使用几个不同的终端在我的系统上得到的结果:
terminator
$ ps --no-headers $(ps -axjf | awk -v pid=$$ '($2==pid){print $1}') | awk '{print $NF}' /usr/bin/x-terminal-emulator
gnome-terminal
$ ps --no-headers $(ps -axjf | awk -v pid=$$ '($2==pid){print $1}') | awk '{print $NF}' /usr/lib/gnome-terminal/gnome-terminal-server
xterm
$ ps --no-headers $(ps axjf | awk -v pid=$$ '($2==pid){print $1}') | awk '{print $NF}' xterm
答案3
以下是获取父进程名称或路径的可移植方法:
iTerm2:
$ ps -p $(ps -p $$ -o ppid=) -o comm=
/Applications/iTerm.app/Contents/MacOS/iTerm
Ubuntu 中的 gnome-terminal:
$ ps -p $(ps -p $$ -o ppid=) -o comm=
gnome-terminal
终端.app:
$ ps -p $(ps -p $$ -o ppid=) -o comm=
login
请注意,如果将 Terminal.app 设置为使用默认登录 shell 打开新 shell,则 shell 的父进程是login
而不是终端。
该comm
列是OS X中命令的完整路径,以及Linux中procps实现中截断为15个字符的命令名称。