简短总结
要找到当前正在运行的shell,请使用ls -l /proc/$$/exe
要找到当前正在运行的终端,请使用xprop _NET_WM_PID WM_CLASS。稍后,pid的值可以传递给ps -p
从技术上讲,对于终端仿真器,您甚至不需要一个命令,正如评论中所述:
你说的“哪个”是什么意思?点击帮助-->关于就可以了吗?- JoKeR
Shell与终端
首先,我们需要搞清楚的是具体在问什么 - 找出正在运行的shell或正在运行的终端。通常这两个术语可以互换使用,但它们是完全不同的东西。Shell是命令行解释器,特别是交互式shell是提示符加文本字段,您可以在其中输入命令。Shell也可以是非交互式的,例如脚本启动非交互式shell,或者bash -c 'echo hello world'也会启动非交互式shell。
相比之下,终端是与shell(尽管也可能是其他应用程序)进行交互的界面。最初,终端指的是实际的硬件设备,但现在它们大多是软件。当您按下Ctrl+Alt+t或在GUI中点击终端图标时,会启动一个终端仿真器,即一个模拟硬件行为的窗口,在该窗口中您可以看到正在运行的shell。按下Ctrl+Alt+F2(或任何6个功能键)将打开虚拟控制台,也称为tty。我建议阅读Why is a virtual terminal “virtual”, and what/why/where is the “real” terminal?以获取更多详细信息。
获取shell信息
每个用户在/etc/passwd中都有一个默认的shell分配给他们的用户名。假设您正在使用默认配置,并且没有显式地调用另一个shell作为命令,只需执行以下操作即可:
echo $SHELL
当然,这只是显示默认值。假设我们进行以下操作:
user@ubuntu:~$ dash
$
我们最初使用的是bash,但开始了/bin/dash的交互会话,Ubuntu的POSIX或系统shell。变量$SHELL不会改变,因为这不是它的目的 - 它显示的是默认值而不是当前值。我们需要从另一个角度来解决这个问题 - 进程的角度,这是我在“我是在使用bash还是sh?”中讨论过的内容。
$ echo $$
4824
$ cat /proc/4824/comm
mksh
$ bash
xieerqi@eagle:~$ echo $$
6197
xieerqi@eagle:~$ cat /proc/6197/comm
bash
在这里,我们利用了/proc/文件系统。进程的名称和命令行参数显示在/proc/
cat /proc/$$/comm
变化的主题也可以是
ps -p $$ -o args
另一种我们可以采用的方法是通过检查/proc/
user@ubuntu:~$ ls -l /proc/$$/exe
lrwxrwxrwx 1 adminx adminx 0 Apr 4 18:20 /proc/1241/exe -> /bin/bash
user@ubuntu:~$ sh
$ ls -l /proc/$$/exe
lrwxrwxrwx 1 adminx adminx 0 Apr 4 18:20 /proc/1255/exe -> /bin/dash
两种方法在99%的情况下都有效。当然,它们也有被规避的方式。例如,如果在shell启动后不久删除了可执行文件,符号链接将指向任何地方(在这种情况下,您可能会遇到系统问题,因为不建议删除/bin/sh、/bin/dash或者/bin/bash - 毕竟许多脚本依赖于它们,尤其是系统级的脚本)。shell的命令名称通常作为execve()系统调用的第一个参数设置。关于这一点,在How does bash know how it is being invoked?中有详细说明,因此如果您有一个通过execve()启动shell的应用程序,它可以使用任何名称。但这些都是非标准和非典型的事情,出于一致性和安全性的考虑,应该避免使用。
获取终端信息
我们可以从环境变量开始。许多终端似乎将自己伪装成xterm兼容的终端,可以通过echo $TERM或echo $COLORTERM来查看。但是环境变量并不是非常可靠的工具。它们可以被设置和取消设置。我们可以再次使用进程ID来做同样的事情,只不过这次我们会查看父进程ID。正如您可能记得的那样,终端是与shell交互的界面,并且通常启动shell本身。因此,我们可以找出哪个进程是我们的shell的父进程:
$ ps -p $$ -o args,ppid
COMMAND PPID
bash 1234
$ ps -p 1234 -o args
COMMAND
/usr/lib/gnome-terminal/gnome-terminal-server
让我们尝试另一个终端应用程序,sakura:
$ ps -p $$ -o args,ppid
COMMAND PPID
/bin/bash 16950
$ ps -p 16950 -o args
COMMAND
sakura
从那里我们已经可以看到,启动这个shell的是gnome-terminal。当然,这种方法假设你正在使用交互式shell。如果我们试图找出bash -c '...'的父进程或者通过ssh启动的shell,PID很可能来自非终端应用程序,甚至可能根本不是GUI。
所以,如果我们想要专门处理GUI终端,我们可以运行xprop,点击所需的窗口,grep其pid,并找出与pid匹配的进程的名称。换句话说:
$ ps aux | grep $(xprop | awk -F'=' '/PID/ {print $2}')
xieerqi 2124 0.6 1.7 208068 34604 ? Sl 18:47 1:49 gnome-terminal
此外,根据规格要求,窗口管理器应该设置WM_CLASS属性。因此,我们也可以通过xprop来获取这个属性:
$ xprop WM_CLASS
WM_CLASS(STRING) = "sakura", "Sakura"
当然,这也有其1%的缺点:设置WM_CLASS属性依赖于窗口管理器的操作,并且PID不能保证窗口的准确性(参见What process created this X11 window?),这可能涉及复杂的调试。而这些并不是方法本身的缺陷,而是X11服务器的缺陷。然而,大多数稳定和知名的窗口管理器(如openbox、Metacity、blackbox)和大多数应用程序都表现良好,所以我们不应该期望在像Gnome Terminal或Terminator这样的应用上出现问题。
但是,当涉及到图形用户界面终端仿真器时,我们甚至不需要找到一个命令。我们可以直接使用窗口本身的“关于”对话框。唯一例外的是xterm。