Skąd mam wiedzieć, ile jestem głębokich skorup pośrednich?

40

Czasami robię takie rzeczy, jak uruchamianie podpowłoki z vima :sh. Skąd mam wiedzieć, że jestem w podpowłoce, w której exitzwrócę mnie tylko o jeden poziom, w porównaniu do bycia w najbardziej zewnętrznej powłoce, w której exitwyloguję się lub zamknę sesję.

Czy istnieje jakiś totem Incepcji, który mogę obrócić, lub coś, aby dowiedzieć się, ile poziomów jestem głęboki?

Wyck
źródło
5
Powiązane na vi.stackexchange.com: Skąd mam wiedzieć, że jestem w powłoce z polecenia vi: sh?
steeldriver
1
Cześć! Jednym z szybkich sposobów sprawdzenia, czy jesteś w podpowłoce, czy nie echo $0. Jeśli jest to powłoka najwyższego poziomu, prawdopodobnie zacznie się od myślnika. (Dotyczy to przynajmniej bash, a myślnik oznacza, że ​​jest to tak zwana powłoka logowania.)
jpaugh

Odpowiedzi:

40

Możesz użyć polecenia pstree(domyślnie dostarczanego z Ubuntu). Oto przykład - obecnie mam tylko jedno otwarte okno terminala na 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}

W rzeczywistym środowisku Linux / Ubuntu drzewo procesów będzie bardziej skomplikowane. Możemy przefiltrować drzewo według opcji -s, która pokaże rodziców wybranego procesu. Więc naszym poleceniem może być pstree -s $$, gdzie $$jest zmienna środowiskowa, która zawiera bieżący 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

Bibliografia:


Dodaj wskaźnik do zachęty powłoki: na podstawie pomysłu @ waltinator , aby mieć licznik z przodu pytania dla kilku różnych powłok, gdy poziom jest głębszy niż jeden, dodałem linie pokazane poniżej wersji demonstracyjnej, u dołu odpowiednich plików komend uruchamiania ( ~/.*rc).

Testowałem na WSL, Ubuntu 16.04, Ubuntu 18.04 (serwer / pulpit), Ubuntu 19.04, w ramach sesji gnome-terminal, tty i ssh. Oto jak to działa:

wprowadź opis zdjęcia tutaj

Ograniczeniem jest to, że: licznik działa tylko dla 13-14 poziomów głębokości, w zależności od systemu operacyjnego. Nie zamierzam badać przyczyn :)

  • 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
    
  • cshi 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
    
  • shtak naprawdę jest dashna Ubuntu - tutaj rzeczy są nieco skomplikowane i okablowane (przeczytaj poniższe informacje, aby uzyskać więcej informacji):

    1. Edytuj ~/.profileplik i dodaj następujący wiersz na dole:

      ENV=$HOME/.shrc; export ENV
    2. Utwórz plik ~/.shrco następującej treści, uwaga kshrównież czyta $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
      

Bibliografia:


Utwórz polecenie, które wyświetli głębokość: Inną opcją jest utworzenie polecenia powłoki, które wyświetli głębokość. W tym celu utwórz plik wykonywalny (dlatego powinien być dostępny dla całego systemu):/usr/local/bin/depth

sudo touch /usr/local/bin/depth
sudo chmod +x /usr/local/bin/depth

Edytuj plik za pomocą swojego ulubionego edytora i dodaj następujące wiersze jako jego zawartość:

#!/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

Powyższy skrypt ma dwie opcje -vlub --verbosewyświetla listę zaangażowanych powłok. I inna opcja, która sprawdzi, czy głębokość jest większa niż jedna i na tej podstawie powróci exit 0lub exit 1, abyś mógł z niej korzystać w ten sposób depth && exit. Oto kilka przykładów użycia:

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

Porównanie z innymi rozwiązaniami: spędziłem trochę czasu, aby dowiedzieć się o słabościach przedstawionych tutaj podejść. Byłem w stanie wyobrazić sobie następujące dwa przypadki (wielkie litery są potrzebne do lepszego podświetlenia składni):

  • Kiedy sulub sudo -isą zaangażowani:

    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
    
  • Po uruchomieniu procesu w tle:

    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
    
pa4080
źródło
Teraz jestem zaskoczony o wyjście mam w moim systemie: systemd───xfce4-terminal───bash───pstree. Dlaczego tak jest?
val
1
@val: systemd jest procesem inicjującym, nadrzędnym dla wszystkich innych procesów. Najwyraźniej używasz xfce4-terminal, który uruchomił bashpowłokę, w której działałeś pstree, która zgłosiła siebie i swoich rodziców. Jeśli masz na myśli brak kroków między systemd a xfce4-terminal, może to oznaczać, że cokolwiek uruchomiony terminal xfce4 umarł lub odrzucił go, w takim przypadku zostałby odziedziczony przez init.
Nick Matteo
Czy jest jakiś powód, żeby nie czytać SHLVL? Zakładam, że można przenosić procesy i systemy, ale nie można zainstalować
pstree
Witam, @ D.BenKnoble, jak to jest omawiane w ramach @ Egmont za odpowiedź , $SHLVLnie jest obsługiwany przez niektóre muszli. Mówiąc dokładniej, zgodnie ze środowiskiem z powyższej wersji demonstracyjnej nie jest obsługiwany tylko przez sh( dash) - i ta powłoka nie jest w ogóle liczona przez tę zmienną. Z drugiej strony pstreejest częścią pakietu Psmisc który zapewnia również fuser, killalli kilku innych - jest głównym składnikiem Ubuntu - nie mam zainstalowany w systemach wymienionych w tej odpowiedzi.
pa4080
30

Sprawdź wartość SHLVLzmiennej powłoki:

echo $SHLVL

Cytowanie ze bashstrony podręcznika:

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

Jest również obsługiwany przez zsh.

egmont
źródło
4
Ale sh nie jest liczony, więc podany przykład z sh nie zwiększyłby SHLVL. Jest to jednak coś, co może być przydatne dla tych, którzy nie zmieniają zbytnio powłok
Ubfan1
3
@ ubfan1, chyba że istnieje nadrzędna definicja vimrc, :shmyślę, że domyślnie jest to powłoka logowania użytkownika (myślę, że jest to w rzeczywistości skrócona forma, :shella nie nazwa konkretnego pliku binarnego powłoki)
steeldriver
3
Nie jestem zaznajomiony ze szczegółami vim, ale starałem się :shz vimprzed wysłaniem tej odpowiedzi, a nie przyrost poziomu powłoki dla mnie. Moja powłoka logowania to bash.
egmont
9

W mojej .bashrcużywam $SHLVLdo dostosowania $PS1, dodając +znaki „ ” do mojej $SUBSHELLzmiennej:

...
# 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
...

Następnie widzę, jak głęboko jestem:

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)$ 
waltinator
źródło
4

awk:

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

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)$')

Możesz umieścić jedną z dwóch wersji w pliku i użyć źródła, aby udostępnić $ 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}"
bac0n
źródło
2

Możesz po prostu użyć psbez dodatkowych argumentów, aby zobaczyć cały stos powłoki (w tym bieżący). Będzie również pokazywał wszystkie zadania w tle, które podjąłeś, a także pssiebie, ale może dać przybliżoną ocenę tego, jak głęboko jesteś.

aragaer
źródło
Działa to, { echo hello world; ps; } &aby potwierdzić pspowyższą odpowiedź.
WinEunuuchs2Unix
@ WinEunuuchs2Unix, mam na myśli coś takiego: paste.ubuntu.com/p/6Kfg8TqR9V
pa4080
Czy istnieje sposób naśladowania pstree -s $$ za pomocą ps?
bac0n