如何从脚本中识别终端?

如何从脚本中识别终端?

不要说“ $TERM”——总是xterm

脚本如何bash知道它在哪个终端运行,具体是 iTerm、Terminal.app 还是实际上是 xterm?

我之所以问这个问题,是因为resetTerminal.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-terminaliTerm 才能发送正确的转义序列。

有什么办法(即使我需要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}'

这是我使用几个不同的终端在我的系统上得到的结果:

  1. terminator

    $ ps --no-headers $(ps -axjf | awk -v pid=$$ '($2==pid){print $1}') | 
       awk '{print $NF}'
    /usr/bin/x-terminal-emulator
    
  2. gnome-terminal

    $ ps --no-headers $(ps -axjf | awk -v pid=$$ '($2==pid){print $1}') | 
       awk '{print $NF}'
    /usr/lib/gnome-terminal/gnome-terminal-server
    
  3. 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个字符的命令名称。

相关内容