Ubuntu 20.04 上的 shell 级别问题

Ubuntu 20.04 上的 shell 级别问题

以下命令针对 ubuntu 20.04 获得返回值 1,但针对 ubuntu 18.04 获得返回值 0,

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

根本原因是我们在针对不同的 ubuntu 版本运行命令时有不同的 $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

针对 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 ']'

答案1

环顾四周,这个问题在邮件bug-bash列表, 在哪里斯蒂芬·查泽拉斯尽管这可能是因为修复了行为SHLVL当 bash 进行尾部调用优化时。

本质上,当您执行 时bash -c 'simple-command',bash 通常会执行优化:它不会先fork执行 然后再exec执行simple-command,而是直接exec执行简单命令。这是一种常见的优化,其他 shell(如 zsh)也会执行相同的操作。以前,在某些情况下,它会被错误地更改,并且会进行更改来修复该问题,这破坏了此特定用途。

例如,在 18.04 的 bash 4.4-19 中,SHLVL即使没有启动新进程,你也可以看到 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 +++

我认为,问题出在检查 上.bash_logout,我认为这不够精确。仅仅检查SHLVL是不够的,如果要清除终端,还应该检查它是否真的在终端中运行。例如[ -t 0 ]

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

在我看来,这是 Ubuntu(好吧,Debian)的一个错误.bash_logout,应该报告为一个错误。SHLVL不是标准的,所以我认为当 shell 可以进行可能影响其值的优化时,它不足以成为唯一的测试。

相关内容