我怎么知道我有多少个子壳深度?

我怎么知道我有多少个子壳深度?

有时我会做一些事情,比如用 从 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
    
  • cshtcsh> .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 上 - 这里的事情有点复杂和连线(阅读下面的参考资料了解更多信息):

    1. 编辑~/.profile文件并在底部添加以下行:

      ENV=$HOME/.shrc; export ENV
      
    2. ~/.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
      

参考:


创建一个输出深度的命令:另一个选项是创建输出深度的 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 0exit 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

与其他解决方案的比较:我花了一些额外的时间来找出这里提供的方法的一些弱点。我能够想象以下两种情况(需要大写字母才能更好地突出显示语法):

  • 何时susudo -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它本身,但它可以粗略地估计您的深度。

相关内容