problema a nivel de shell en ubuntu 20.04

problema a nivel de shell en ubuntu 20.04

el siguiente comando obtuvo un valor de retorno 1 contra ubuntu 20.04, pero 0 contra ubuntu 18.04,

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

La causa principal es que tenemos diferentes valores de $SHLVL cuando ejecutamos el comando en diferentes versiones de Ubuntu, entonces, ¿es este el comportamiento esperado?

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

y el resultado del mismo comando ejecutándose en 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 ']'

Respuesta1

Mirando a su alrededor, esto se ha discutido un poco enlas bug-bashlistas de correo, dóndeStéphane Chazelasaunque sería debido auna solución en el comportamiento deSHLVLcuando bash realiza la optimización de llamadas de cola.

Esencialmente, cuando lo haces bash -c 'simple-command', bash generalmente realiza una optimización: en lugar de forkejecutar y luego execejecutar el comando simple-command, ejecuta directamente execel comando simple. Esta es una optimización común; otros shells como zsh también hacen lo mismo. Anteriormente, en algunos casos se cambiaba incorrectamente y se realizó un cambio para solucionarlo, lo que interrumpió este uso en particular.

Por ejemplo, en bash 4.4-19 de 18.04, puede ver el SHLVLget incrementado aunque no se haya iniciado ningún proceso nuevo:

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

Este habría sido el comportamiento correcto con una bifurcación, como cuando no se realiza esa optimización:

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

Esto se solucionó en bash 5.0, donde:

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

Donde esto va mal, en mi opinión, es en el check in .bash_logout, que creo que no es lo suficientemente preciso. Simplemente verificar SHLVLno es suficiente; si va a borrar el terminal, también debe verificar si realmente se está ejecutando en un terminal. Algo como [ -t 0 ]:

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

Esto es, en mi humilde opinión, un error en Ubuntu (bueno, en Debian) .bash_logouty debería informarse como tal. SHLVLno es estándar, por lo que no creo que sea lo suficientemente bueno como para ser la única prueba cuando los shells pueden realizar optimizaciones que podrían afectar su valor.

información relacionada