Sco*_*ott 47
当我读到你的问题时,我的第一个想法是$SHLVL
。然后,我看到你想算vim
的水平
,除了外壳的水平。一个简单的方法是定义一个shell函数:
vim() { ( ((SHLVL++)); command vim "$@");}
Run Code Online (Sandbox Code Playgroud)
SHLVL
每次键入vim
命令时,这都会自动且无提示地递增。您将需要为您曾经使用过的vi
/ 的每个变体执行此操作vim
;例如,
vi() { ( ((SHLVL++)); command vi "$@");}
view() { ( ((SHLVL++)); command view "$@");}
Run Code Online (Sandbox Code Playgroud)
外面的一组括号创建了一个子shell,因此手动更改 的值SHLVL
不会污染当前(父)shell 环境。当然,command
关键字是为了防止函数调用自己(这会导致无限递归循环)。当然,您应该将这些定义放入您的.bashrc
或其他 shell 初始化文件中。
上面有一点效率低下。在某些 shell 中(bash 是其中之一),如果你说
( cmd 1 ; cmd 2 ; ... ; cmd n )
如果是外部的可执行程序(即不是内置命令),shell 会保留一个额外的进程,只是为了等待终止。这(可以说)没有必要;优点和缺点值得商榷。如果您不介意占用一点内存和一个进程槽(并且在执行 a 时看到比您需要的更多的 shell 进程),那么请执行上述操作并跳到下一部分。如果您使用的外壳不会保留额外的进程,则同上。但是,如果你想避免额外的过程,首先要尝试的是cmdn
cmdn
ps
vim() { ( ((SHLVL++)); exec vim "$@");}
Run Code Online (Sandbox Code Playgroud)
该exec
命令是为了防止额外的 shell 进程逗留。
但是,有一个问题。shell 对 的处理SHLVL
有点直观:当 shell 启动时,它会检查是否SHLVL
已设置。如果未设置(或设置为数字以外的其他值),shell 会将其设置为 1。如果已设置(设置为数字),shell 会将其加 1。
但是,按照这个逻辑,如果你说exec sh
,你SHLVL
应该上升。但这是不可取的,因为您的真实外壳级别并没有增加。外壳通过从执行以下操作
时减去一个来 处理此问题:SHLVL
exec
$ echo "$SHLVL"
1
$ set | grep SHLVL
SHLVL=1
$ env | grep SHLVL
SHLVL=1
$ (env | grep SHLVL)
SHLVL=1
$ (env) | grep SHLVL
SHLVL=1
$ (exec env) | grep SHLVL
SHLVL=0
Run Code Online (Sandbox Code Playgroud)
所以
vim() { ( ((SHLVL++)); exec vim "$@");}
Run Code Online (Sandbox Code Playgroud)
是洗;它增加SHLVL
只会再次减少它。您不妨直接说vim
,而没有功能的好处。
注意:
根据 Stéphane Chazelas(他什么都知道)的说法,如果位于子shell 中,一些shell 足够聪明,不会这样做exec
。
要解决这个问题,你会这样做
vim() { ( ((SHLVL+=2)); exec vim "$@");}
Run Code Online (Sandbox Code Playgroud)
然后我看到,你想算vim
水平
独立的外壳水平。好吧,完全相同的技巧有效(好吧,稍作修改):
vim() { ( ((SHLVL++, VILVL++)); export VILVL; exec vim "$@");}
Run Code Online (Sandbox Code Playgroud)
(对于vi
、view
等,依此类推)export
是必需的,因为VILVL
默认情况下未将其定义为环境变量。但它不需要成为函数的一部分;你可以只说export?VILVL
一个单独的命令(在你的.bashrc
)。并且,如上所述,如果额外的 shell 进程对您来说不是问题,您可以使用command?vim
代替exec?vim
,并且不用管SHLVL
:
vim() { ( ((VILVL++)); command vim "$@");}
Run Code Online (Sandbox Code Playgroud)
个人偏好:
您可能希望重命名VILVL
为VIM_LEVEL
. 看着“VILVL
”,我的眼睛很痛;他们无法分辨这是“vinyl”的拼写错误还是格式错误的罗马数字。
如果您使用的外壳不支持SHLVL
(例如,破折号),只要外壳实现启动文件,您就可以自己实现它。只是做类似的事情
if [ "$SHELL_LEVEL" = "" ]
then
SHELL_LEVEL=1
else
SHELL_LEVEL=$(expr "$SHELL_LEVEL" + 1)
fi
export SHELL_LEVEL
Run Code Online (Sandbox Code Playgroud)
在您的.profile
或适用的文件中。(您可能不应该使用 name SHLVL
,因为如果您开始使用支持 的 shell,这会导致混乱SHLVL
。)
其他答案已经解决了将环境变量值嵌入到 shell 提示中的问题,所以我不会重复,尤其是你说你已经知道怎么做。
Sté*_*las 37
您可以计算需要向上爬过程树的次数,直到找到会话负责人。就像zsh
在 Linux 上一样:
lvl() {
local n=0 pid=$$ buf
until
IFS= read -rd '' buf < /proc/$pid/stat
set -- ${(s: :)buf##*\)}
((pid == $4))
do
((n++))
pid=$2
done
echo $n
}
Run Code Online (Sandbox Code Playgroud)
或 POSIXly(但效率较低):
lvl() (
unset IFS
pid=$$ n=0
until
set -- $(ps -o ppid= -o sid= -p "$pid")
[ "$pid" -eq "$2" ]
do
n=$((n + 1)) pid=$1
done
echo "$n"
)
Run Code Online (Sandbox Code Playgroud)
这将为您的终端模拟器或 getty 启动的 shell 提供 0,并为每个后代提供一个。
您只需要在启动时执行一次。例如:
PS1="[$(lvl)]$PS1"
Run Code Online (Sandbox Code Playgroud)
在您的~/.zshrc
或等效的提示中包含它。
tcsh
和其他几发炮弹(zsh
,ksh93
,fish
和bash
至少)保持$SHLVL
他们在启动时增加变量(运行另一个命令之前和递减exec
(除非exec
是在子shell,如果他们不是越野车(但很多)))。这只跟踪外壳嵌套的数量,而不是进程嵌套。同样,级别 0 也不能保证是会话领导者。
Joh*_*ohn 16
一种可能的解决方案是查看 的输出pstree
。当在从 inside 产生的 shell 中运行时vi
,列出的树树部分pstree
应该告诉你你有多深。例如:
$ pstree <my-user-ID>
...
??gnome-terminal-???bash???vi???sh???vi???sh???pstree
...
Run Code Online (Sandbox Code Playgroud)
Min*_*Max 11
简单的解决方案bash
:添加到.bashrc
接下来的两行(或更改您的当前PS1
值):
PS1="${SHLVL} \w\$ "
export PS1
Run Code Online (Sandbox Code Playgroud)
结果:
1 ~$ bash
2 ~$ bash
3 ~$ exit
exit
2 ~$ exit
exit
1 ~$
Run Code Online (Sandbox Code Playgroud)
提示字符串开头的数字表示shell级别。
将此行添加到 .bashrc
branch=$(pstree -ls $$)
vim_lvl=$(grep -o vim <<< "$branch" | wc -l)
sh_lvl=$(grep -o bash <<< "$branch" | wc -l)
PS1="v:${vim_lvl};s:$((sh_lvl - 1)):\w\$ "
export PS1
Run Code Online (Sandbox Code Playgroud)
结果:
v:0;s:1:/etc$ bash
v:0;s:2:/etc$ bash
v:0;s:3:/etc$ vim
##### do ':sh' command in the vim, shell level is increasing by 1
v:1;s:4:/etc$ vim
##### do ':sh' command in the vim, shell level is increasing by 1
v:2;s:5:/etc$ bash
v:2;s:6:/etc$
Run Code Online (Sandbox Code Playgroud)
v:1 - vim 深度级别
s:3 - shell 深度级别
在您提到解析pstree
. 这里有一个比较简单的方法:
bash-4.3$ pstree -Aals $$ | grep -E '^ *`-((|ba|da|k|c|tc|z)sh|vim?)( |$)'
`-bash
`-bash --posix
`-vi -y
`-dash
`-vim testfile.txt
`-tcsh
`-csh
`-sh -
`-zsh
`-bash --norc --verbose
Run Code Online (Sandbox Code Playgroud)
该pstree
选项:
-A
- ASCII 输出以便于过滤(在我们的例子中,每个命令都以 开头`-
)-a
- 还显示命令参数,作为副作用,每个命令都显示在单独的行中,我们可以使用以下命令轻松过滤输出 grep
-l
- 不要截断长行-s
- 显示所选进程的父进程pstree
)$$
- 选择的进程 - 当前 shell 的 PID 归档时间: |
|
查看次数: |
13153 次 |
最近记录: |