使用sed和pstree来显示正在使用的terminal的types

我一直在试图显示仅作为名称使用的terminal的types。 例如,如果我使用konsole,它会显示konsole。 到目前为止,我一直在使用这个命令。

pstree -A -s $$ 

输出这个。

 systemd---konsole---bash---pstree 

我有以下可以从该行中提取konsole

 pstree -A -s $$ | sed 's/systemd---//g;s/---.*//g' | head -1 

并正确输出konsole。 但是,有些人只是从pstree命令的输出,可以看起来像这样。

 systemd---kdeinit4---terminator---bash---pstree 

或这个

 systemd---kdeinit4---lxterminal---bash---pstree 

然后当我添加sed命令时,它会提取kdeinit4而不是终止符。 我可以想到一些情景提取terminal的types,但没有包含条件语句来检查特定types的terminal。 我遇到的问题是我无法准确预测terminal名称前面或后面有多less非相关或不相关的东西,或者它们是什么,我也无法准确预测terminal名称。 有没有人有任何想法解决这个问题?

你可以使用

 ps -p "$PPID" -o comm= 

要么

 ps -p "$PPID" -o fname= 

如果你的shell没有设置PPID变量,你可以使用它

 ps -p "$(ps -p "$$" -o ppid= | sed 's|\s\+||')" -o fname= 

另一个理论是,当前shell的父进程不属于与shell相同的tty实际上可能是产生虚拟终端的那个进程,所以我们也可以这样做:

 #!/bin/bash shopt -s extglob SHELLTTY=$(exec ps -p "$$" -o tty=) P=$$ while read P < <(exec ps -p "$P" -o ppid=) && [[ $P == +([[:digit:]]) ]]; do if read T < <(exec ps -p "$P" -o tty=) && [[ $T != "$SHELLTTY" ]]; then ps -p "$P" -o comm= break fi done 

我不知道如何隔离你系统上的终端名称,但作为一个解析练习,假设终端直接运行你的bash,你可以通过管道输出pstree:

  awk -F"---bash---" ' NF == 2 { count = split( $1, arr, "---" ); print arr [count]; }' 

这会在你的例子中找到“— bash —”之前的单词

 konsole terminator lxterminal 

如果你想要不同的shell类型,你可以扩展字段分隔符来包含它们:

 awk -F"---(bash|csh)---" ' NF == 2 { count = split( $1, arr, "---" ); print arr[count]; }' 

考虑一个想象的线如:

 systemd---imaginary---monkey---csh---pstree 

awk会发现“猴子”作为终端名称以及测试集中的任何内容。

没有保证在这里,但我认为这将工作在Linux上的大部分时间:

 ps -ocomm= $(lsof -tl /proc/$$/fd/0 | grep -Fxf <(lsof -t /dev/ptmx)) 

一个小小的解释可能是有序的,但看到man psman lsof和(尤其是) man pts的信息。

/dev/ptmx是一个伪tty主(在现代linux系统上,以及一些其他的类Unix系统)。 如果程序是终端仿真程序,telnet / ssh守护程序或其他需要捕获终端的程序(例如, screen ,程序将会打开其中一个程序。 仿真器向伪tty主机写入它想要“输入”的内容,并从伪tty从机读取结果。

/proc/$$/fd/0是进程$$标准输入(即执行该命令的shell)。 如果stdin没有被重定向,那么这将是一个从属伪元件/ dev / pts /#的符号链接。 这是/ dev / ptmx设备的另一端,因此上面列出的所有具有/dev/ptmx打开的程序也会打开一些/dev/pts/#从属设备。 (你可能认为你可以使用/dev/stdin/dev/fd/0而不是/proc/$$/fd/0 ,但是这些会被lsof本身打开,因此会成为stdin; lsof的实现方式是行不通的。) lsof-l选项会导致它跟随符号链接,这样会导致它显示与当前shell具有相同pts的进程。

lsof-t选项导致它产生“terse”输出,只包含pid,每行一个。 grep-Fx选项使它匹配字符串,而不是正则表达式,强制全行匹配; -f FILE选项使它接受要从FILE (在这种情况下是进程替换)匹配的字符串,每行一个。

最后, ps -ocomm=打印出与pid对应的“命令”(默认为8个字符)。

简而言之,该命令找到一个终端仿真程序和其他主要类似程序的列表,这些程序具有一个主伪程序,以及一个使用伪程序从程序的进程列表; 找到两者之间的交集,然后查找命令名称以得到任何结果。

 curTerm=$(update-alternatives --query x-terminal-emulator | grep '^Best:') curTerm=${curTerm##*/} printf "%s\n" "$curTerm" 

结果是

 terminator 

当然可以有所不同。
现在你可以在你的sed命令中使用$curTerm变量。

但是我不确定这是否能正常工作与符号链接。