有时我会做一些事情,比如用:sh
. 我怎么知道我是否在一个子 shell 中,在那里exit
我只会让我退出一个级别,而不是在最外层的 shell 中,在那里exit
我会注销或关闭我的会话。
有没有什么我可以旋转的盗梦空间图腾或者什么东西可以知道我的深度是多少?
pa4*_*080 45
您可以使用该命令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}
Run Code Online (Sandbox Code Playgroud)
在实际的 Linux/Ubuntu 环境中,进程树会更加复杂。我们可以通过-s
将显示选定进程的父进程的选项过滤树。所以我们的命令可以是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
Run Code Online (Sandbox Code Playgroud)
参考:
在 shell 的提示中添加指示符:基于@waltinator 的想法,为了在级别大于 1 时在提示前为多个不同的 shell 设置一个计数器,我添加了以下行,如下所示,在相关运行命令( ~/.*rc
) 文件的底部。
我已经在 gnome-terminal、tty 和 ssh 会话中对 WSL、Ubuntu 16.04、Ubuntu 18.04(服务器/桌面)、Ubuntu 19.04 进行了测试。这是它的工作原理:
限制在于:计数器仅适用于 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
Run Code Online (Sandbox Code Playgroud)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
Run Code Online (Sandbox Code Playgroud)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
Run Code Online (Sandbox Code Playgroud)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
Run Code Online (Sandbox Code Playgroud)sh
这实际上是dash
在 Ubuntu 上——这里的事情有点复杂和连线(阅读下面的参考资料以获取更多信息):
编辑~/.profile
文件并在底部添加以下行:
ENV=$HOME/.shrc; export ENV
Run Code Online (Sandbox Code Playgroud)创建~/.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
Run Code Online (Sandbox Code Playgroud)参考:
.profile
和.kshrc
创建将输出深度的命令:另一种选择是创建将输出深度的 shell 命令。为此,创建可执行文件(因此它应该可以在系统范围内访问):/usr/local/bin/depth
sudo touch /usr/local/bin/depth
sudo chmod +x /usr/local/bin/depth
Run Code Online (Sandbox Code Playgroud)
使用您喜欢的编辑器编辑该文件并添加以下行作为其内容:
#!/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
Run Code Online (Sandbox Code Playgroud)
上面的脚本有两个选项,-v
或者--verbose
将输出所涉及 shell 的列表。另一个选项将检查深度是否大于一个并基于此返回exit 0
or 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
Run Code Online (Sandbox Code Playgroud)
与其他解决方案的比较:我花了一些额外的时间来找出这里提供的方法的一些弱点。我能够想象以下两种情况(需要大写字母才能更好地突出显示语法):
当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
Run Code Online (Sandbox Code Playgroud)启动后台进程时:
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
Run Code Online (Sandbox Code Playgroud)egm*_*ont 31
检查SHLVL
shell变量的值:
echo $SHLVL
Run Code Online (Sandbox Code Playgroud)
引用bash
的手册页:
SHLVL Incremented by one each time an instance of bash is started.
Run Code Online (Sandbox Code Playgroud)
它也得到zsh
.
在我的 中.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
...
Run Code Online (Sandbox Code Playgroud)
然后,我可以看到我有多深:
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)$
Run Code Online (Sandbox Code Playgroud)