우분투 20.04의 쉘 레벨 문제

우분투 20.04의 쉘 레벨 문제

다음 명령은 우분투 20.04에 대해 1의 반환 값을 얻었지만 우분투 18.04에 대해서는 0을 얻었습니다.

$ ssh user@remote bash -exl -c 'exit 0'

근본 원인은 다른 우분투 버전에서 명령을 실행할 때 $SHLVL 값이 다르기 때문에 이것이 예상되는 동작입니까?

+ '[' '' ']'
+ '[' -d /etc/profile.d ']'
+ for i in /etc/profile.d/*.sh
+ '[' -r /etc/profile.d/01-locale-fix.sh ']'
+ . /etc/profile.d/01-locale-fix.sh
+++ /usr/bin/locale-check C.UTF-8
++ eval
+ for i in /etc/profile.d/*.sh
+ '[' -r /etc/profile.d/apps-bin-path.sh ']'
+ . /etc/profile.d/apps-bin-path.sh
++ snap_bin_path=/snap/bin
++ '[' -n /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games -a -n /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games ']'
++ export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
++ PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
++ '[' -z '' ']'
++ export XDG_DATA_DIRS=/usr/local/share:/usr/share
++ XDG_DATA_DIRS=/usr/local/share:/usr/share
++ snap_xdg_path=/var/lib/snapd/desktop
++ '[' -n /usr/local/share:/usr/share -a -n /usr/local/share:/usr/share ']'
++ export XDG_DATA_DIRS=/usr/local/share:/usr/share:/var/lib/snapd/desktop
++ XDG_DATA_DIRS=/usr/local/share:/usr/share:/var/lib/snapd/desktop
+ for i in /etc/profile.d/*.sh
+ '[' -r /etc/profile.d/bash_completion.sh ']'
+ . /etc/profile.d/bash_completion.sh
++ '[' 'x5.0.17(1)-release' '!=' x -a x '!=' x -a x = x ']'
+ for i in /etc/profile.d/*.sh
+ '[' -r /etc/profile.d/cedilla-portuguese.sh ']'
+ . /etc/profile.d/cedilla-portuguese.sh
++ '[' en = pt -a en '!=' pt ']'
+ for i in /etc/profile.d/*.sh
+ '[' -r /etc/profile.d/gawk.sh ']'
+ . /etc/profile.d/gawk.sh
+ for i in /etc/profile.d/*.sh
+ '[' -r /etc/profile.d/Z97-byobu.sh ']'
+ . /etc/profile.d/Z97-byobu.sh
++ '[' -r /usr/bin/byobu-launch ']'
++ '[' '' = 0 ']'
++ '[' '' = 1 ']'
++ '[' -e /etc/byobu/autolaunch ']'
++ '[' '' = byobu ']'
++ '[' '' = byobu-screen ']'
++ '[' '' = byobu-tmux ']'
+ unset i
+ '[' -n '5.0.17(1)-release' ']'
+ '[' -f /home/jenkins/.bashrc ']'
+ . /home/jenkins/.bashrc
++ case $- in
++ return
+ '[' -d /home/jenkins/bin ']'
+ PATH=/home/jenkins/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
+ exit
++ '[' 1 = 1 ']'
++ '[' -x /usr/bin/clear_console ']'
++ /usr/bin/clear_console -q

우분투 18.04에 대해 실행되는 동일한 명령의 출력,

+ '[' '' ']'
+ '[' -d /etc/profile.d ']'
+ for i in /etc/profile.d/*.sh
+ '[' -r /etc/profile.d/01-locale-fix.sh ']'
+ . /etc/profile.d/01-locale-fix.sh
+++ /usr/bin/locale-check C.UTF-8
++ eval
+ for i in /etc/profile.d/*.sh
+ '[' -r /etc/profile.d/apps-bin-path.sh ']'
+ . /etc/profile.d/apps-bin-path.sh
++ snap_bin_path=/snap/bin
++ '[' -n /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games -a -n /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games ']'
++ export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
++ PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
++ '[' -z '' ']'
++ export XDG_DATA_DIRS=/usr/local/share:/usr/share
++ XDG_DATA_DIRS=/usr/local/share:/usr/share
++ snap_xdg_path=/var/lib/snapd/desktop
++ '[' -n /usr/local/share:/usr/share -a -n /usr/local/share:/usr/share ']'
++ export XDG_DATA_DIRS=/usr/local/share:/usr/share:/var/lib/snapd/desktop
++ XDG_DATA_DIRS=/usr/local/share:/usr/share:/var/lib/snapd/desktop
+ for i in /etc/profile.d/*.sh
+ '[' -r /etc/profile.d/bash_completion.sh ']'
+ . /etc/profile.d/bash_completion.sh
++ '[' -n '4.4.20(1)-release' -a -n '' -a -z '' ']'
+ for i in /etc/profile.d/*.sh
+ '[' -r /etc/profile.d/cedilla-portuguese.sh ']'
+ . /etc/profile.d/cedilla-portuguese.sh
++ '[' en = pt -a en '!=' pt ']'
+ for i in /etc/profile.d/*.sh
+ '[' -r /etc/profile.d/Z97-byobu.sh ']'
+ . /etc/profile.d/Z97-byobu.sh
++ '[' -r /usr/bin/byobu-launch ']'
++ '[' '' = 0 ']'
++ '[' '' = 1 ']'
++ '[' -e /etc/byobu/autolaunch ']'
++ '[' '' = byobu ']'
++ '[' '' = byobu-screen ']'
++ '[' '' = byobu-tmux ']'
+ unset i
+ '[' -n '4.4.20(1)-release' ']'
+ '[' -f /home/jenkins/.bashrc ']'
+ . /home/jenkins/.bashrc
++ case $- in
++ return
+ '[' -d /home/jenkins/bin ']'
+ PATH=/home/jenkins/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
+ exit
++ '[' 2 = 1 ']'

답변1

주위를 둘러보면 이 내용이 어느 정도 논의된 바 있습니다.메일 bug-bash링 리스트, 어디스테판 차젤라스그 이유 때문이겠지만행동의 수정SHLVLbash가 tail call 최적화를 수행할 때.

기본적으로 를 수행할 때 bash -c 'simple-command'bash는 일반적으로 최적화를 수행합니다. 즉, forking을 수행한 다음 exec를 수행하는 대신 간단한 명령을 simple-command직접 수행합니다 . exec이것은 일반적인 최적화이며 zsh와 같은 다른 쉘도 동일한 작업을 수행합니다. 이전에는 일부 경우 잘못 변경되었으며 이를 수정하기 위해 변경이 이루어졌는데, 이로 인해 이 특정 용도가 중단되었습니다.

SHLVL예를 들어, 18.04의 bash 4.4-19에서는 새 프로세스가 시작되지 않았더라도 get이 증가하는 것을 볼 수 있습니다 .

# env SHLVL=0 strace -fe execve bash -c 'bash -c "declare -p SHLVL"'
execve("/bin/bash", ["bash", "-c", "bash -c \"declare -p SHLVL\""], 0x7ffd6525c6f0 /* 8 vars */) = 0
execve("/bin/bash", ["bash", "-c", "declare -p SHLVL"], 0x562fd3b437e0 /* 8 vars */) = 0
declare -x SHLVL="2"

이는 최적화가 완료되지 않은 경우와 같이 포크를 사용한 올바른 동작이었을 것입니다.

# env SHLVL=0 strace -fe execve bash -c ':; bash -c "declare -p SHLVL"'
execve("/bin/bash", ["bash", "-c", ":; bash -c \"declare -p SHLVL\""], 0x7ffea8bb7c30 /* 8 vars */) = 0
strace: Process 284 attached
[pid   284] execve("/bin/bash", ["bash", "-c", "declare -p SHLVL"], 0x55fe735077e0 /* 8 vars */) = 0
declare -x SHLVL="2"
[pid   284] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=284, si_uid=0, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++

이는 bash 5.0에서 수정되었습니다.

% env SHLVL=0 strace -fe execve bash -c 'bash -c "declare -p SHLVL"'
execve("/usr/bin/bash", ["bash", "-c", "bash -c \"declare -p SHLVL\""], 0x7ffc70b6cd20 /* 59 vars */) = 0
execve("/usr/bin/bash", ["bash", "-c", "declare -p SHLVL"], 0x55f22a0343a0 /* 59 vars */) = 0
declare -x SHLVL="1"
+++ exited with 0 +++

이것이 잘못되는 곳은 IMO가 체크인 중인데 .bash_logout, 충분히 정확하지 않다고 생각합니다. 단순히 확인하는 것만으로는 SHLVL충분하지 않습니다. 터미널을 지우려면 실제로 터미널에서 실행되고 있는지도 확인해야 합니다. 다음과 같은 것 [ -t 0 ]:

  -t FD          True if FD is opened on a terminal.

이것은 우분투(뭐, 데비안)의 버그인 IMHO .bash_logout이며 하나로 보고되어야 합니다. SHLVL표준이 아니기 때문에 쉘이 그 가치에 영향을 미칠 수 있는 최적화를 수행할 수 있는 경우 유일한 테스트가 되기에는 충분하지 않다고 생각합니다.

관련 정보