Shell-Level-Problem unter Ubuntu 20.04

Shell-Level-Problem unter Ubuntu 20.04

Der folgende Befehl lieferte einen Rückgabewert von 1 unter Ubuntu 20.04, aber 0 unter Ubuntu 18.04.

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

die Grundursache liegt darin, dass wir unterschiedliche $SHLVL-Werte haben, wenn wir den Befehl für unterschiedliche Ubuntu-Versionen ausführen. Ist das also das erwartete Verhalten?

+ '[' '' ']'
+ '[' -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

und die Ausgabe des gleichen Befehls unter Ubuntu 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 ']'

Antwort1

Wenn man sich umschaut, wird dies bereits diskutiert indie bug-bashMailinglisten, WoStéphane Chazelasobwohl es daran liegen würde,eine Korrektur im Verhalten vonSHLVLwenn Bash eine Tail-Call-Optimierung durchführt.

Wenn Sie dies tun bash -c 'simple-command', führt Bash im Wesentlichen eine Optimierung durch: Anstatt forking und dann execing auszuführen simple-command, führt es direkt execden einfachen Befehl aus. Dies ist eine gängige Optimierung, andere Shells wie zsh machen dasselbe. Früher wurde es in einigen Fällen falsch geändert, und es wurde eine Änderung vorgenommen, um das zu beheben, was diese spezielle Verwendung unterbrach.

Beispielsweise können Sie in der Bash 4.4-19 von 18.04 sehen, dass SHLVL„get“ erhöht wird, obwohl kein neuer Prozess gestartet wurde:

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

Dies wäre das richtige Verhalten bei einer Fork gewesen, beispielsweise wenn diese Optimierung nicht durchgeführt wird:

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

Dies wurde in Bash 5.0 behoben, wo:

% 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 +++

Meiner Meinung nach ist der Fehler beim Einchecken .bash_logout, das meiner Meinung nach nicht präzise genug ist. Einfach nur nach zu suchen , SHLVLreicht nicht aus. Wenn das Terminal gelöscht werden soll, sollte auch geprüft werden, ob es tatsächlich in einem Terminal ausgeführt wird. So etwas wie [ -t 0 ]:

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

Meiner Meinung nach handelt es sich hierbei um einen Fehler in Ubuntu (also Debian) .bash_logoutund sollte als solcher gemeldet werden. SHLVLEs handelt sich nicht um Standard, daher halte ich es nicht für gut genug, um der einzige Test zu sein, wenn Shells Optimierungen vornehmen können, die seinen Wert beeinflussen könnten.

verwandte Informationen