有时我会做一些事情,比如用 从 vim 启动子 shell :sh
。我如何知道我是否在子 shell 中,其中exit
只会让我退出一级,还是在最外层的 shell 中,其中exit
会让我退出或关闭我的会话。
是否存在某种我可以旋转的盗梦图腾或其他东西来让我知道我深度有多少层?
答案1
您可以使用命令pstree
(Ubuntu 默认自带)。以下是示例 - 目前我在 WSL 上只打开了一个终端窗口:
User@Wsl:~$ pstree
init─┬─init───bash───pstree
└─{init}
User@Wsl:~$ bash
User@Wsl:~$ sh
$ bash
User@Wsl:~$ pstree
init─┬─init───bash───bash───sh───bash───pstree
└─{init}
-s
在实际的 Linux/Ubuntu 环境中,进程树会更加复杂。我们可以通过显示所选进程的父进程的选项来过滤树。因此我们的命令可以是pstree -s $$
,其中$$
是包含当前 PID 的环境变量:
User@Ubuntu:~$ pstree -s $$
systemd──lightdm──lightdm──upstart──gnome-terminal-──bash──pstree
User@Ubuntu:~$ bash
User@Ubuntu:~$ sh
$ bash
User@Ubuntu:~$ pstree -s $$
systemd──lightdm──lightdm──upstart──gnome-terminal-──bash──bash──sh──bash──pstree
参考:
在 shell 的提示符中添加指示符:根据@waltinator的主意为了在级别大于 1 时在提示符前面为几个不同的 shell 提供一个计数器,我在相关提示符的底部添加了以下几行,如演示所示运行命令(~/.*rc
)文件。
我已经在 WSL、Ubuntu 16.04、Ubuntu 18.04(服务器/桌面)、Ubuntu 19.04 的 gnome-terminal、tty 和 ssh 会话中进行了测试。工作原理如下:
限制是:计数器仅适用于 13-14 级深度,具体取决于操作系统。我不打算调查原因 :)
bash
>.bashrc
:DEPTH=$(($(pstree -s $$ | sed -r 's/-+/\n/g' | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh)\>') - 1)) if (( DEPTH > 1 )); then PS1=$DEPTH:$PS1; fi
csh
和tcsh
>.cshrc
:@ DEPTH = `pstree -s $$ | sed -r 's/-+/\n/g' | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh)\>'` - 0 if ( $DEPTH > 1 ) then; set prompt="$DEPTH":"$prompt"; endif
zsh
>.zshrc
:DEPTH=$(($(pstree -s $$ | sed -r 's/-+/\n/g' | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh)\>') - 1)) if (( DEPTH > 1 )); then PROMPT=$DEPTH:$PROMPT; fi
ksh
>.kshrc
:DEPTH=$(($(pstree -s $$ | sed -r 's/\-+/\n/g' | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh)\>') - 0)) if (( DEPTH > 1 )); then PS1="$DEPTH":"$PS1"'$ '; fi
sh
这实际上是dash
在 Ubuntu 上 - 这里的事情有点复杂和连线(阅读下面的参考资料了解更多信息):编辑
~/.profile
文件并在底部添加以下行:ENV=$HOME/.shrc; export ENV
~/.shrc
创建包含以下内容的文件,ksh
另请注意$ENV
:#!/bin/dash DEPTH=$(pstree -s $$ | sed -r 's/-+/\n/g' | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh)\>') if [ "$0" != 'ksh' ]; then DEPTH=$((DEPTH - 1)); fi if [ "$DEPTH" -gt 1 ]; then export PS1='$DEPTH:\$ '; fi
参考:
- 答案的先前版本,计数器仅在 Bash 中起作用
- Unix&Linux:/etc 目录中是否有一个供 dash 和 sh 作为非登录 shell 调用的文件?
- Ubuntu 手册:Dash(阅读 BUGS 部分)
- UnixWare 7 文档:Korn shell
.profile
和.kshrc
创建一个输出深度的命令:另一个选项是创建输出深度的 shell 命令。为此,请创建可执行文件(因此它应该可在整个系统范围内访问):/usr/local/bin/depth
sudo touch /usr/local/bin/depth
sudo chmod +x /usr/local/bin/depth
使用您喜欢的编辑器编辑该文件并添加以下行作为其内容:
#!/bin/bash
SHELLS='(bash|zsh|sh|dash|ksh|csh|tcsh)'
DEPTH=$(pstree -s $$ | sed -r 's/-+/\n/g' | grep -Ec "\<$SHELLS\>")
if [[ $@ =~ -v ]]
then
pstree -s $$ | sed -r 's/-+/\n/g' | grep -E "\<$SHELLS\>" | cat -n
fi
echo "DEPTH: $DEPTH"
[[ $DEPTH -gt 1 ]] && exit 0 || exit 1
上述脚本有两个选项-v
或 ,--verbose
将输出相关 shell 的列表。另一个选项将检查深度是否大于 1,并据此返回exit 0
或exit 1
,因此您可以这样使用它depth && exit
。以下是一些使用示例:
User@Ubuntu:~$ depth # we are at the 1st level - bash
DEPTH: 1
User@Ubuntu:~$ sh
$ csh # we are at the 2nd level - dash
Ubuntu:~% depth # we are at the 3rd level - csh
DEPTH: 3
Ubuntu:~% ksh
$ depth -v # we are at the 4th level - ksh
1 bash
2 sh
3 csh
4 ksh
DEPTH: 4
$ depth && exit # exit to the 3rd level - csh
DEPTH: 4
Ubuntu:~% depth && exit # exit to the 2nd level - dash
DEPTH: 3
exit
$ depth && exit # exit to the 1st level - bash
DEPTH: 2
User@Ubuntu:~$ depth && exit # stay at the 1st level - bash
DEPTH: 1
User@Ubuntu:~$ depth && exit # stay at the 1st level - bash
DEPTH: 1
与其他解决方案的比较:我花了一些额外的时间来找出这里提供的方法的一些弱点。我能够想象以下两种情况(需要大写字母才能更好地突出显示语法):
何时
su
或sudo -i
涉及:User@Ubuntu:~$ ps | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh|su|sudo)\>' 1 User@Ubuntu:~$ echo $SHLVL 1 User@Ubuntu:~$ depth DEPTH: 1 User@Ubuntu:~$ su spas Password: Spas@Ubuntu:~$ ps | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh|su|sudo)\>' 1 Spas@Ubuntu:~$ echo $SHLVL 2 Spas@Ubuntu:~$ depth DEPTH: 2 Spas@Ubuntu:~$ sudo -i [sudo] password for spas: Root@Ubuntu:~# ps | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh|su|sudo)\>' 3 Root@Ubuntu:~# echo $SHLVL 1 Root@Ubuntu:~# depth DEPTH: 3
当启动后台进程时:
User@Ubuntu:~$ bash User@Ubuntu:~$ ps | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh)\>' 2 User@Ubuntu:~$ echo $SHLVL 2 User@Ubuntu:~$ depth DEPTH: 2 User@Ubuntu:~$ while true; do sleep 10; done & [1] 10886 User@Ubuntu:~$ ps | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh)\>' 3 User@Ubuntu:~$ echo $SHLVL 2 User@Ubuntu:~$ depth DEPTH: 2 # Note: $SHLVL is not supported only by sh/dash. # It works with all other tested shells: bash, zsh, csh, tcsh, ksh User@Ubuntu:~$ sh $ ps | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh)\>' 4 $ echo $SHLVL 2 $ depth DEPTH: 3
答案2
检查shell变量的值SHLVL
:
echo $SHLVL
引用bash
自的手册页:
SHLVL Incremented by one each time an instance of bash is started.
它也得到了 的支持zsh
。
答案3
在我的 中.bashrc
,我通过将“ ”符号附加到我的变量 $SHLVL
来调整:$PS1
+
$SUBSHELL
...
# set a variable to reflect SHLVL > 1 (Ubuntu 12.04)
if [[ $SHLVL -gt 1 ]] ; then
export SUBSHELL="${SUBSHELL:+$SUBSHELL}+"
else
export SUBSHELL=""
fi
...
if [[ "$color_prompt" = yes ]]; then
# chroot? Depth green user@host nocolor : green $PWD red (status) off $ or # space
PS1='${debian_chroot:+($debian_chroot)}${SUBSHELL}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[1;31m\]($?)\[\033[00m\]\$ '
else
PS1='${debian_chroot:+($debian_chroot)}${SUBSHELL}\u@\h:\w\$ '
fi
...
然后,我就能看出我有多深了:
walt@bat:~(1)$ ed foo
263
!bash
+walt@bat:~(0)$ bash
++walt@bat:~(0)$ bash
+++walt@bat:~(0)$ exit
exit
++walt@bat:~(0)$ exit
exit
+walt@bat:~(0)$ exit
exit
!
q
walt@bat:~(0)$
答案4
您只需使用ps
而不使用任何附加参数即可查看整个 shell 堆栈(包括当前堆栈)。它还将显示您已启动的所有后台作业以及ps
它本身,但它可以粗略地估计您的深度。