Как я могу узнать, сколько у меня подуровней?

Иногда я делаю такие вещи, как запуск суб-оболочки из vim с :sh. Как я узнаю, что если я нахожусь в подчиненной оболочке, где exit просто вернет меня на один уровень, вместо того, чтобы находиться в самой внешней оболочке, где exit выведет меня из системы или закроет мой сеанс.

Есть ли какой-нибудь тотем Начала, который я могу вращать, или что-то, чтобы узнать, на каком уровне я нахожусь?

40
задан 27 September 2019 в 20:09

5 ответов

Можно использовать команду 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}

В фактической среде 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

Ссылки:


Добавьте индикатор к подсказке оболочки: На основе идеи @waltinator, чтобы иметь счетчик перед подсказкой для нескольких различных оболочек, когда уровень глубже, чем один, я добавил строки, показанные ниже демонстрации, у основания соответствующих команд выполнения (~/.*rc) файлы.

Я сделал тесты на WSL, Ubuntu 16.04, Ubuntu 18.04 (сервер/рабочий стол), Ubuntu 19.04, в терминале гнома, tty и ssh сессии. Вот то, как это работает:

enter image description here

Ограничение то, что: счетчик работает только на 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 - здесь вещи являются немного сложными и соединены проводом (считайте ссылки ниже для получения дополнительной информации):

    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
      

Ссылки:


Создайте команду, которая произведет глубину: Другая опция состоит в том, чтобы создать команду оболочки, которая произведет глубину. С этой целью создайте исполняемый файл /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 это произведет список включенных оболочек. И другая опция, которая проверит, больше ли глубина, чем одна и на основе этого, возвратится 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
    
40
ответ дан 23 October 2019 в 10:12

Проверьте значение SHLVL переменная оболочки:

echo $SHLVL

Заключение в кавычки от bash страница руководства:

SHLVL  Incremented by one each time an instance of bash is started.

Это также поддерживается zsh.

30
ответ дан 23 October 2019 в 10:12

В моем .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)$ 
9
ответ дан 23 October 2019 в 10:12

awk:

# Count the occurrence of (sh)ells.
DEPTH_REGEX='^(ash|bash|busybox|csh|dash|fish|mksh|sh|tcsh|zsh) 

pgrep:

DEPTH=$(/usr/bin/pgrep -c -s $(/bin/ps -p $ -osid --no-headers) '^(ash|bash|busybox|csh|dash|fish|mksh|sh|tcsh|zsh) 

можно поместить одну из этих двух версий в файле и использовать источник для предоставления доступа к $DEPTH доступным.

# Set 256 colors in terminal.
if [ -x /usr/bin/tput ] && [ "$(SHELL=/bin/sh tput colors)" -ge 8 ]; then
    export TERM="xterm-256color"
fi

# change these if you don't dig my colors!

NM="\[\033[0;1;37m\]"   #means no background and white lines
HI="\[\033[0;37m\]"     #change this for letter colors
SI="\[\033[38;5;202m\]" #this is for the current directory
NI="\[\033[0;1;30m\]"   #for @ symbol
IN="\[\033[0m\]"

# Count the occurrence of (sh)ells.
source /usr/share/shell-depth/depth

PS1="${NM}[${HI}\u${NI}@${HI}\h ${SI}\w${NM} \A](${HI}${DEPTH}${NM}): ${IN}"
)

можно поместить одну из этих двух версий в файле и использовать источник для предоставления доступа к $DEPTH доступным.

# Set 256 colors in terminal.
if [ -x /usr/bin/tput ] && [ "$(SHELL=/bin/sh tput colors)" -ge 8 ]; then
    export TERM="xterm-256color"
fi

# change these if you don't dig my colors!

NM="\[\033[0;1;37m\]"   #means no background and white lines
HI="\[\033[0;37m\]"     #change this for letter colors
SI="\[\033[38;5;202m\]" #this is for the current directory
NI="\[\033[0;1;30m\]"   #for @ symbol
IN="\[\033[0m\]"

# Count the occurrence of (sh)ells.
source /usr/share/shell-depth/depth

PS1="${NM}[${HI}\u${NI}@${HI}\h ${SI}\w${NM} \A](${HI}${DEPTH}${NM}): ${IN}"
DEPTH=$(/bin/ps -s $(/bin/ps -p $ -osid --no-headers) -ocomm --no-headers | \ awk -v R=$DEPTH_REGEX '{for (A=1; A<=(NR-2); A++) {if ($A ~ R) {B++}}} END {print B}')

pgrep:

DEPTH=$(/usr/bin/pgrep -c -s $(/bin/ps -p $ -osid --no-headers) '^(ash|bash|busybox|csh|dash|fish|mksh|sh|tcsh|zsh) 

можно поместить одну из этих двух версий в файле и использовать источник для предоставления доступа к $DEPTH доступным.

# Set 256 colors in terminal.
if [ -x /usr/bin/tput ] && [ "$(SHELL=/bin/sh tput colors)" -ge 8 ]; then
    export TERM="xterm-256color"
fi

# change these if you don't dig my colors!

NM="\[\033[0;1;37m\]"   #means no background and white lines
HI="\[\033[0;37m\]"     #change this for letter colors
SI="\[\033[38;5;202m\]" #this is for the current directory
NI="\[\033[0;1;30m\]"   #for @ symbol
IN="\[\033[0m\]"

# Count the occurrence of (sh)ells.
source /usr/share/shell-depth/depth

PS1="${NM}[${HI}\u${NI}@${HI}\h ${SI}\w${NM} \A](${HI}${DEPTH}${NM}): ${IN}"
)

можно поместить одну из этих двух версий в файле и использовать источник для предоставления доступа к $DEPTH доступным.

# Set 256 colors in terminal.
if [ -x /usr/bin/tput ] && [ "$(SHELL=/bin/sh tput colors)" -ge 8 ]; then
    export TERM="xterm-256color"
fi

# change these if you don't dig my colors!

NM="\[\033[0;1;37m\]"   #means no background and white lines
HI="\[\033[0;37m\]"     #change this for letter colors
SI="\[\033[38;5;202m\]" #this is for the current directory
NI="\[\033[0;1;30m\]"   #for @ symbol
IN="\[\033[0m\]"

# Count the occurrence of (sh)ells.
source /usr/share/shell-depth/depth

PS1="${NM}[${HI}\u${NI}@${HI}\h ${SI}\w${NM} \A](${HI}${DEPTH}${NM}): ${IN}"
4
ответ дан 23 October 2019 в 10:12

Можно просто использовать ps без любых дополнительных аргументов для наблюдения целой стопки оболочки (включая текущую). Это будет также показывать все фоновые задания, которые Вы запустили, а также ps само, но это может дать Вам грубую оценку того, как глубоко Вы.

2
ответ дан 23 October 2019 в 10:12

Другие вопросы по тегам:

Похожие вопросы: