얼마나 많은 서브 쉘이 있는지 어떻게 알 수 있습니까?


40

때로는 vim에서 sub-shell을 시작하는 등의 작업을 수행 :sh합니다. 내가 exit한 레벨을 반환 하는 하위 셸에 있는지 , exit아니면 로그 아웃하거나 세션을 닫을 수 있는 가장 바깥 쪽 셸에 있는지 어떻게 알 수 있습니까 ?

내가 돌릴 수있는 어떤 종류의 시작 토템이 있습니까?



1
안녕하세요! 서브 쉘에 있는지 여부를 확인하는 빠른 방법 중 하나는 echo $0입니다. 최상위 쉘이라면 아마도 대시로 시작합니다. (이것은 적어도 bash에 해당되며 대시는 소위 로그인 쉘이라는 것을 의미합니다.)
jpaugh

답변:


40

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 's idea 에 따라 레벨이 1보다 깊을 때 여러 쉘에 대한 프롬프트 앞에 카운터를 갖기 위해 데모 아래에 선을 추가했습니다. 관련 실행 명령 ( ~/.*rc) 파일 의 맨 아래에 있습니다.

그놈 터미널, tty 및 ssh 세션 내에서 WSL, Ubuntu 16.04, Ubuntu 18.04 (서버 / 데스크톱), Ubuntu 19.04에서 테스트했습니다. 이것이 작동하는 방법은 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

카운터는 OS에 따라 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우분투에 있습니다. 여기 상황이 약간 복잡하고 연결되어 있습니다 (자세한 내용은 아래 참조를 읽으십시오).

    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관련된 쉘 목록을 출력합니다. 그리고 깊이가이 반환에 1보다 큰 및 기반인지 여부를 확인합니다 다른 옵션 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

이제 시스템에서 얻은 출력에 대해 의아해 systemd───xfce4-terminal───bash───pstree합니다. 왜 이런 식입니까?

1
@val : systemd는 다른 모든 프로세스의 부모 인 init 프로세스입니다. 당신은 분명히 자신과 부모를보고 xfce4-terminalbash쉘 을 시작한을 사용 pstree하고 있습니다. systemd와 xfce4-terminal 사이에 단계가 없다는 것을 의미하는 경우 xfce4-terminal을 시작한 모든 것이 사망했거나 제거 된 것일 수 있으며,이 경우 init에 의해 상속됩니다.
Nick Matteo

읽을 이유가 SHLVL없습니까? 프로세스와 시스템 간의 이식성은 가정하지만 pstree는 설치되지 않을 수 있습니다.
D. Ben Knoble

@egmont의 답변 에서 논의 된 것처럼 @ D.BenKnoble $SHLVL은 일부 쉘에서 지원되지 않습니다. 보다 구체적으로, 위 데모의 환경에 따라 sh( dash) 에서만 지원 되지 않으며이 변수는이 셸을 전혀 계산하지 않습니다. 반면에 pstree패키지의 일부입니다 가운데서도 또한 제공 fuser, killall그리고 몇 가지 다른 - 그것은 우분투의 주요 구성 요소입니다 -이 대답에 언급 된 시스템을 설치하지 않았습니다.
pa4080

30

SHLVL쉘 변수 의 값을 확인하십시오 .

echo $SHLVL

bash의 매뉴얼 페이지 에서 인용 :

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

또한 지원합니다 zsh.


4
그러나 sh는 계산되지 않으므로 sh와 함께 제공된 예제는 SHLVL을 증가시키지 않았을 것입니다. 아직도, 이것은 쉘을 너무 많이
바꾸지

3
대체 vimrc 정의가없는 경우 @ ubfan1 :sh은 사용자의 로그인 쉘로 기본 설정됩니다 ( :shell특정 쉘 바이너리의 이름이 아닌 약식으로
표시됨

3
나는 정력의 세부 사항에 익숙하지 않은,하지만 난 밖으로 해봤 :sh에서 vim이 답변을 게시하기 전에, 그것은 나를 위해 쉘 수준을 증가했다. 내 로그인 쉘은 bash입니다.
egmont

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

그러면 내가 얼마나 깊은 지 알 수 있습니다.

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

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

두 버전 중 하나를 파일에 배치하고 소스를 사용하여 $ 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}"

2

ps추가 인수없이 간단히 사용 하여 전체 쉘 스택 (현재 스택 포함)을 볼 수 있습니다. 또한 자신이 시작한 모든 백그라운드 작업을 보여줄 ps것이지만 얼마나 깊이 있는지 대략적으로 추정 할 수 있습니다.


이것은 위 { echo hello world; ps; } &ps대답 을 증명하기 위해 작동 합니다 .
WinEunuuchs2Unix

@ WinEunuuchs2Unix, 나는 다음과 같은 것을 의미합니다 : paste.ubuntu.com/p/6Kfg8TqR9V
pa4080

pstree -s $$를 ps와 모방하는 방법이 있습니까?
bac0n
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.