내 껍질 깊이는 몇 개인가요?

내 껍질 깊이는 몇 개인가요?

질문: 내가 가지고 있는 껍질이 몇 개인지 알아보세요.

세부 사항: 나는 종종 vim에서 쉘을 엽니다. 빌드하고 실행하고 종료합니다. 때로는 다른 vim을 열고 또 다른 쉘을 여는 것을 잊어버릴 때도 있습니다. :(

내 쉘이 얼마나 깊은지 알고 싶습니다. 어쩌면 내 쉘 화면까지 깊숙이 들어갈 수도 있습니다. (그 부분은 내가 관리할 수 있다.)

내 솔루션: 프로세스 트리를 구문 분석하고 vim 및 bash/zsh를 찾아 현재 프로세스가 얼마나 깊은지 알아보세요.

비슷한 것이 이미 존재합니까? 아무것도 찾을 수 없습니다.

답변1

귀하의 질문을 읽었을 때 가장 먼저 든 생각은 이었습니다 $SHLVL. 그러다가 vim레벨을 계산하고 싶어하는 걸 봤어요또한쉘 수준. 간단한 방법은 쉘 함수를 정의하는 것입니다.

vim()  { ( ((SHLVL++)); command vim  "$@");}

SHLVL 명령을 입력할 때마다 값이 자동으로 자동으로 증가합니다 vim. 예를 들어, /를 사용한 vi모든 변형에 대해 이 작업을 수행 해야 합니다.vim

vi()   { ( ((SHLVL++)); command vi   "$@");}
view() { ( ((SHLVL++)); command view "$@");}

바깥쪽 괄호 그룹은 하위 쉘을 생성하므로 값을 수동으로 변경해 SHLVL 도 현재(상위) 쉘 환경이 오염되지 않습니다. 물론 command키워드의 목적은 함수가 자신을 호출하는 것을 방지하는 것입니다(이로 인해 무한 재귀 루프가 발생함). 물론 이러한 정의를 자신 .bashrc이나 다른 쉘 초기화 파일에 넣어야 합니다.


위의 내용은 약간 비효율적입니다. 일부 쉘에서는 (bash가 그 중 하나입니다) 다음과 같이 말하면

(명령 1; 명령 2;; 명령 n)

외부 실행 프로그램인 경우(즉, 내장 명령이 아님) 쉘은 종료되기를 기다리는 추가 프로세스를 유지합니다. 이는 (아마도) 불필요합니다. 장점과 단점은 논쟁의 여지가 있습니다. 약간의 메모리와 프로세스 슬롯을 차지하는 것이 괜찮다면(그리고 해당 작업을 수행할 때 필요한 것보다 하나 더 많은 셸 프로세스가 표시되는 경우) 위의 작업을 수행하고 다음 섹션으로 건너뜁니다. 추가 프로세스를 유지하지 않는 셸을 사용하는 경우 위와 동일합니다. 하지만, 추가적인 과정을 피하고 싶다면 가장 먼저 시도해 볼 것은cmdncmdnps

vim()  { ( ((SHLVL++)); exec vim  "$@");}

exec명령의 목적은 추가 쉘 프로세스가 돌아다니는 것을 방지하는 것입니다.

그러나 문제가 있습니다. 쉘의 처리는 다소 직관적입니다. 쉘이 시작되면 설정되었는지 SHLVL확인합니다 . SHLVL설정되지 않은 경우(또는 숫자가 아닌 다른 값으로 설정된 경우) 쉘은 이를 1로 설정합니다. 설정하면(숫자로 설정) 쉘은 이를 1씩 증가시킵니다.

하지만 그 논리에 따르면 '라고 하면 올라가야 한다 exec sh. SHLVL실제 쉘 레벨은 증가하지 않으므로 이는 권장되지 않습니다. 쉘은 이 문제를 다음과 같이 처리합니다.마이너스 1~에서 SHLVL 다음을 수행할 때 exec:

$ echo "$SHLVL"
1

$ set | grep SHLVL
SHLVL=1

$ env | grep SHLVL
SHLVL=1

$ (env | grep SHLVL)
SHLVL=1

$ (env) | grep SHLVL
SHLVL=1

$ (exec env) | grep SHLVL
SHLVL=0

그래서

vim()  { ( ((SHLVL++)); exec vim  "$@");}

그것은 세탁입니다; SHLVL다시 감소하기 위해서만 증가합니다. vim기능의 이점 없이 그냥 그렇게 말할 수도 있습니다 .

노트:
모든 것을 알고 있는 Stéphane Chazelas에 따르면, 일부 껍질은 충분히 똑똑합니다.아니요exec서브셸에 있는 경우 이 작업을 수행하세요.

이 문제를 해결하려면 다음을 수행하십시오.

vim()  { ( ((SHLVL+=2)); exec vim  "$@");}

vim그러다가 레벨을 계산하고 싶어하는 걸 봤어요독립쉘 수준. 음, 똑같은 트릭이 작동합니다(약간만 수정하면 됩니다).

vim() { ( ((SHLVL++, VILVL++)); export VILVL; exec vim "$@");}

vi(for 등 view)은 기본적으로 환경 변수로 정의되지 않으므로 export필수입니다 . 그러나 함수의 일부일 필요는 없습니다. 별도의 명령으로 VILVL말할 수 있습니다 (귀하의 명령에서 ). 그리고 위에서 언급한 것처럼 추가 쉘 프로세스가 문제가 되지 않으면 다음을 수행할 수 있습니다 .export VILVL.bashrccommand vimexec vimSHLVL

vim() { ( ((VILVL++)); command vim "$@");}

개인 취향:
VILVL비슷한 이름으로 바꿀 수도 있습니다 VIM_LEVEL. " "를 보면 VILVL눈이 아팠습니다 . "vinyl"의 철자가 틀린 것인지 로마 숫자의 실수인지 알 수 없었습니다.


사용 중인 셸이 이를 지원하지 않는 경우 SHLVL(예: 대시) 셸이 시작 파일을 구현하는 한 직접 구현할 수 있습니다. 그냥 다음과 같이 해보세요

if [ "$SHELL_LEVEL" = "" ]
then
    SHELL_LEVEL=1
else
    SHELL_LEVEL=$(expr "$SHELL_LEVEL" + 1)
fi
export SHELL_LEVEL

귀하 .profile또는 해당 파일에. ( SHLVL지원되는 shell 을 사용하기 시작하면 혼란을 야기할 수 있으므로 names 를 사용하면 안 됩니다 SHLVL.)


다른 답변에서는 이미 환경 변수 값을 쉘 프롬프트에 포함시키는 문제를 다루었으므로 특히 이 작업을 수행하는 방법을 이미 알고 있다고 말씀하셨기 때문에 반복하지 않겠습니다.

답변2

세션 리더를 찾을 때까지 프로세스 트리를 조회하는 데 걸리는 횟수를 셀 수 있습니다. zshLinux에서와 마찬가지로 :

lvl() {
  local n=0 pid=$$ buf
  until
    IFS= read -rd '' buf < /proc/$pid/stat
    set -- ${(s: :)buf##*\)}
    ((pid == $4))
  do
    ((n++))
    pid=$2
  done
  echo $n
}

또는 POSIXly(그러나 덜 효율적):

lvl() (
  unset IFS
  pid=$$ n=0
  until
    set -- $(ps -o ppid= -o sid= -p "$pid")
    [ "$pid" -eq "$2" ]
  do
    n=$((n + 1)) pid=$1
  done
  echo "$n"
)

이는 터미널 에뮬레이터 또는 getty에 의해 시작된 쉘에 대해 0을 제공하고 각 하위 항목에 대해 1을 제공합니다.

시작 시 한 번만 수행하면 됩니다. 예를 들어:

PS1="[$(lvl)]$PS1"

귀하 또는 이에 상응하는 콘텐츠 ~/.zshrc의 프롬프트에 이를 포함시키십시오 .

tcsh그리고 몇몇 다른 쉘( zsh, ksh93, fish적어도 bash) $SHLVL은 시작 시 증가하는 변수를 유지합니다(그리고 다른 명령을 실행하기 전에 감소합니다 exec( exec서브 쉘에 오류가 없는 경우(그러나 많은 경우 오류가 발생하는 경우)는 제외)). 수량만 추적합니다.껍데기그러나 중첩된 프로세스가 아니라 중첩된 프로세스입니다. 또한 레벨 0이 세션 리더가 될 수도 없습니다.

답변3

사용 echo $SHLVL. 사용키스의 원리. 프로그램의 복잡성에 따라 이 정도면 충분할 수도 있습니다.

답변4

첫 번째 변형 - 쉘 깊이만 해당됩니다.

간단한 해결책 bash: .bashrc다음 두 줄에 추가하십시오(또는 현재 PS1값을 변경하십시오).

PS1="${SHLVL} \w\$ "
export PS1

결과:

1 ~$ bash
2 ~$ bash
3 ~$ exit
exit
2 ~$ exit
exit
1 ~$

프롬프트 문자열 시작 부분의 숫자는 쉘 레벨을 나타냅니다.

두 번째 변형에는 중첩된 vim 및 셸 수준이 모두 있습니다.

이 줄을 다음에 추가하십시오..bashrc

branch=$(pstree -ls $$)
vim_lvl=$(grep -o vim <<< "$branch" | wc -l)
sh_lvl=$(grep -o bash <<< "$branch" | wc -l)
PS1="v:${vim_lvl};s:$((sh_lvl - 1)):\w\$ "
export PS1

결과:

v:0;s:1:/etc$ bash
v:0;s:2:/etc$ bash
v:0;s:3:/etc$ vim
##### do ':sh' command in the vim, shell level is increasing by 1
v:1;s:4:/etc$ vim
##### do ':sh' command in the vim, shell level is increasing by 1
v:2;s:5:/etc$ bash
v:2;s:6:/etc$

v:1 - vim 깊이 수준
s:3 - 쉘 깊이 수준

관련 정보