如何从命令行获取当前终端的名称?

有没有可能通过命令获取终端的类型?
如果我使用的是gnome-terminal,输出应该是gnome-terminal或类似的内容。同时,能够获取终端的版本信息也会很好。
更新:
ps -aux | grep `ps -p $$ -o ppid=` 

会输出类似这样的内容:
user     4239  0.0  0.7 292708 15744 pts/8    Sl   11:39   0:02 xfce4-terminal
user     4800  0.0  0.0   6176   820 pts/0    S+   12:23   0:00 grep --color=auto  4239

这个方法也适用于xterm,但是我怎样才能只获取名称(在这种情况下是xfce4-terminal)呢?

我刚刚用一种不同且更好的方法更新了我的答案。如果你有时间,看一下并告诉我它对你是否也有效。 - terdon
谢谢,但是首先遇到了一个关于rxvt的问题 -> 窗口31457282没有与之关联的pid(在Lubuntu上测试过) - TuKsn
哦?该死,那真奇怪。我是在Cinnamon下进行测试的。 - terdon
7个回答

一种方法是获取当前shell会话的父进程,然后从中获取终端的名称。
获取当前 shell 进程的父进程。Bash 变量 `$$` 是你当前 shell 的 PID,因此我们可以将其作为一个查询参数传递给 `ps`(`-p $$`),并要求它打印父进程的 PID (`-o ppid=`,末尾的 `=` 是为了避免打印列标题):
```sh $ ps -p $$ -o ppid= 544 ```
所以,我的shell的父进程的PID是544。
获取与该PID相关联的进程,并打印其命令行。
``` $ ps -p 544 o args= /usr/bin/python /usr/bin/terminator ```
上述输出将取决于您使用的终端仿真器,我正在使用terminator。
  • 将所有内容合并为一个命令

     ps -p $(ps -p $$ -o ppid=) -o args=
    
  • 使用该命令获取版本信息

     $(ps -p $(ps -p $$ -o ppid=) o args=) --version
     terminator 0.97
    
  • ~/.bashrc中添加一个小函数,用于返回您正在使用的终端仿真器的名称和版本(适用于大多数常见终端仿真器):

     which_term(){
         term=$(ps -p $(ps -p $$ -o ppid=) -o args=);
         found=0;
         case $term in
             *gnome-terminal*)
                 found=1
                 echo "gnome-terminal " $(dpkg -l gnome-terminal | awk '/^ii/{print $3}')
                 ;;
             *lxterminal*)
                 found=1
                 echo "lxterminal " $(dpkg -l lxterminal | awk '/^ii/{print $3}')
                 ;;
             rxvt*)
                 found=1
                 echo "rxvt " $(dpkg -l rxvt | awk '/^ii/{print $3}')
                 ;;
             ## 尝试猜测其他终端仿真器
             *)
                 for v in '-version' '--version' '-V' '-v'
                 do
                     $term "$v" &>/dev/null && eval $term $v && found=1 && break
                 done
                 ;;
         esac
         ## 如果没有任何版本参数起作用,则尝试获取软件包版本
         [ $found -eq 0 ] && echo "$term " $(dpkg -l $term | awk '/^ii/{print $3}')    
     }
    
  • 现在您可以获取终端的名称,并向其传递任何您喜欢的选项(例如--version)。
    以下是使用不同终端的一些示例:
    1.

    xterm

     $ which_term
     XTerm(297)
    

    2.

    terminator

     $ which_term 
     terminator 0.97
    

    3.

    rxvt,这个没有-V-version或者--version标志,所以没有打印版本信息。

     $  which_term
     rxvt  1:2.7.10-5
    

    4.

    gnome-terminal

     $ which_term
     gnome-terminal  3.10.1-1
    

    5.

    konsole

     $ which_term
     Qt: 4.8.6
     KDE Development Platform: 4.11.3
     Konsole: 2.11.3
    

    6.

    lxterminal

     $ which_term
     lxterminal  0.1.11-4
    

    7.

    xfce4-terminal

     $ which_term
     xfce4-terminal 0.6.2 (Xfce 4.10)
    
     版权所有 (c) 2003-2012
         Xfce开发团队。保留所有权利。
    
     由Benedikt Meurer <benny@xfce.org>和Nick Schermer <nick@xfce.org>编写。
    
     请将错误报告发送至<http://bugzilla.xfce.org/>。
    

    新的和改进的

    尽管上述方法不太可靠。当您在切换到另一个用户后运行shell或者终端被别名为其他内容时,它会出现问题。由于我们显然是在这里使用X程序,更好的方法可能是使用类似xdotool(可通过sudo apt-get install xdotool安装)来获取信息:

    perl -lpe 's/\0/ /g' /proc/$(xdotool getwindowpid $(xdotool getactivewindow))/cmdline
    

    以上将打印用于启动当前活动窗口的命令行。由于您的终端应该是活动状态,所以它将显示该命令。这意味着对于大多数终端仿真器,您可以安全地假设返回的第一个字段是终端名称:
    $ which_term 
    lxterminal 
    

    这意味着获取版本是微不足道的。例如,
    $ dpkg -l $(which_term) | awk '/^ii/{print $3}'
    0.1.11-4
    

    对于gnome-terminal来说并非如此:
    $ which_term 
    /usr/lib/gnome-terminal/gnome-terminal-server 
    

    或者终结者:
    $ which_term
    /usr/bin/python /usr/bin/terminator 
    

    所以,我们可以让它变得更复杂一些(这里有一些bash特性,这个不是可移植的):
    which_term(){
        term=$(perl -lpe 's/\0/ /g' \
               /proc/$(xdotool getwindowpid $(xdotool getactivewindow))/cmdline)
    
        ## Enable extended globbing patterns
        shopt -s extglob
        case $term in
            ## If this terminal is a python or perl program,
            ## then the emulator's name is likely the second 
            ## part of it
            */python*|*/perl*    )
             term=$(basename "$(readlink -f $(echo "$term" | cut -d ' ' -f 2))")
             version=$(dpkg -l "$term" | awk '/^ii/{print $3}')
             ;;
            ## The special case of gnome-terminal
            *gnome-terminal-server* )
              term="gnome-terminal"
            ;;
            ## For other cases, just take the 1st
            ## field of $term
            * )
              term=${term/% */}
            ;;
         esac
         version=$(dpkg -l "$term" | awk '/^ii/{print $3}')
         echo "$term  $version"
    }
    

    这对我测试过的所有情况都有效。

    @Xubu-Tur 嗯,我只是尝试手动从另一个终端启动每个终端,并且一切都正常。我猜测你的桌面环境菜单可能有不同的路径,或者在启动终端方面存在差异。如果你告诉我你是如何启动它们以及遇到了什么错误,我也许能给你更好的建议。如果你是从菜单中启动的,请检查菜单项运行的命令是什么。 - terdon
    @Xubu-Tur 不要添加屏幕截图。只需将错误消息粘贴到您的问题中。对于菜单项启动的任何命令也是如此。不要指望我从图片中手动复制它! - terdon
    2你可以直接使用$PPID来获取父进程的PID。 - alexia
    @nyuszika7h 是的,你可以这样做,我也赞同,但我宁愿不这样做。我刚刚检查了一下,kshtcsh 中没有这个选项。对于 bash 家族来说,这是一个非常好的主意,因为它比我的方法简单得多。 - terdon
    它绝对可以在 ksh93mksh 中使用。 - alexia
    @nyuszika7h 是的,确实抱歉,fishcshtcsh不可用。那个ksh应该是csh - terdon
    这些外壳无论如何都有不同的语法,而且大多数人都会期望使用bash,因为它是默认的。 - alexia
    我觉得我发现了一个拼写错误 :)$(ps -p $(ps -p $$ -o ppid=) o args=) --version第二个 o 应该是 -o: $(ps -p $(ps -p $$ -o ppid=) -o args=) --version - s6mike
    1其实,两种都可以,@s6mike。o(不带-)是BSD格式,而大多数Linux系统(包括Ubuntu)附带的ps命令支持-oo两种格式。但你说得对,这确实容易让人困惑,使用相同的格式更清晰,所以我进行了编辑。谢谢! - terdon

    basename "$(cat "/proc/$PPID/comm")"
    

    $PPID 是 shell 的父进程的 PID。 comm 表示命令。它可能是完整路径,也可能不是,所以我们使用 basename 来去除路径(如果需要的话)。

    注意事项

    这些注意事项可能也适用于其他答案。

    • comm 在技术上是 argv[0],实际上可以是任意字符串。但一般来说,在这个特定情况下,你应该能够依赖它。

    • 如果您通过 SSH 连接或使用 tmuxscreen 或类似的工具,这将无法按预期工作。


    这非常好+1,但在终结者终端上我只得到termin作为输出。 - TuKsn
    我不知道为什么,可能是《终结者》的错。 - alexia
    我认为这是因为它是作为 Python 脚本运行的。这真的很烦人。 - terdon
    请注意,$PPID 在所有的 shell 中并不是标准的。例如,在 tcsh 中我得到的是:PPID: 未定义的变量。 - arielf

    试试这个,
    ps -aux | grep `ps -p $$ -o ppid=` | awk 'NR==1{print $11}'
    

    或者

    ps -aux | grep `ps -p $$ -o ppid=` | awk 'NR==1{print $NF}'
    

    第一个在rxvtterminator上失败,第二个在uxtermgnome-terminal上失败(它打印/usr/lib/gnome-terminal/gnome-terminal-server)。如果您正在使用su会话,它们都将失败(包括我的)。 - terdon

    另一个(不完美的)可能性是:
    xprop -id $WINDOWID WM_CLASS | cut -d" " -f3 | sed 's/^.\(.*\)..$/\1/'
    

    但是这在lxterminal上不起作用,因为环境变量$WINDOWID为空...
    Terminator显示的名称是"x-terminal-emulator"。

    你可以尝试以下命令:
    $ dpkg-query -W $COLORTERM
    gnome-terminal  3.6.2-0ubuntu1
    

    更新(感谢OP和Avinash Raj):
    $ dpkg-query -W $(ps -aux | grep "`ps -p $$ -o ppid=`" | awk 'NR==1{print $11}' | xargs basename)
    rxvt    1:2.7.10-5
    

    我觉得他想知道的是关于当前活动终端会话的信息 :) 所以如果他当时正在使用 "putty" ... - Rinzwind
    不是关于"putty",而是关于xterm,使用这个命令我也能在xterm中得到gnome-terminal 3.6.2-0ubuntu1l吗? - TuKsn
    2这不会打印出你当前使用的终端。它会打印出已设置为默认$COLORTERM的任何内容,与你当时使用的终端无关。 - terdon
    更新也适用于xterm,并显示版本和名称。 - TuKsn
    所有的功劳归功于@Avinash和你正确的指令。我只是添加了版本。 - Sylvain Pineau

    终端的名称可能在您的环境变量中设置。
    echo $TERM
    

    例子:
    $ echo $TERM
    xterm
    

    1-1,它指定了你使用的终端类型,而不是终端本身。所以举个例子,我正在使用Konsole,但echo $TERM打印出的是xterm-256color - aderchox

    当前终端还可以通过转义序列进行检测:设备属性(Secondary DA)
    例如,在bash中:
    read -s -dc -p $'\E[>c' da;da=${da##$'\E'[>};echo "${da//;/ }"
    

    这只返回一种id——可惜我不知道一个官方的列表能将其翻译成实际名称。
    对于一个真实的实现,可以将一些已知的标识转换为终端名称,请参考这个示例的bash脚本: https://github.com/mintty/utils/blob/master/terminal