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

Wyc*_*yck 46 command-line

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

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

      ENV=$HOME/.shrc; export ENV
      
      Run Code Online (Sandbox Code Playgroud)
    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
      
      Run Code Online (Sandbox Code Playgroud)

参考:


创建将输出深度的命令:另一种选择是创建将输出深度的 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 0or 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)

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

  • 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
    
    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

检查SHLVLshell变量的值:

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.

  • 但是 sh 不计算在内,因此给出的示例,使用 sh,不会增加 SHLVL。尽管如此,这对于那些不太频繁切换 shell 的人来说可能是有用的 (4认同)
  • @ubfan1 除非有一个覆盖 vimrc 定义,我认为 `:sh` 默认为用户的登录 shell(它实际上是 `:shell` 的缩写形式,而不是特定 shell 二进制文件的名称) (3认同)
  • 我不熟悉 vim 的详细信息,但是在发布此答案之前,我已经从 `vim` 中尝试了 `:sh`,它确实为我增加了 shell 级别。我的登录 shell 是 bash。 (3认同)

wal*_*tor 9

在我的 中.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)