循环内的子 shell 中的 continue 或 break 不再起作用

循环内的子 shell 中的 continue 或 break 不再起作用

以下代码可在任意数量的 Linux 发行版的 bash 中运行,包括 CentOS 6.10 - 7.8 和 Ubuntu 14.04 - 18.04。

#!/bin/bash
#
# Test for continue from subshell issue...
#
echo SHELL is $SHELL
for i in $(seq 5)
do
    (
    echo loop $i
    if [[ $i == 2 ]] ; then
        echo i = $i - continue
        continue
    fi

    if [[ $i == 4 ]] ; then
        echo i = $i - exit
        exit 1
    fi
    echo Loop $i subshell end
    )
    rc=$?
    echo Loop $i rc $rc
done

所有这些机器上的输出是:

SHELL is /bin/bash
loop 1
Loop 1 subshell end
Loop 1 rc 0
loop 2
i = 2 - continue
Loop 2 rc 0
loop 3
Loop 3 subshell end
Loop 3 rc 0
loop 4
i = 4 - exit
Loop 4 rc 1
loop 5
Loop 5 subshell end
Loop 5 rc 0

在 Ubuntu 20.04 计算机上:

SHELL is /bin/bash
loop 1
Loop 1 subshell end
Loop 1 rc 0
loop 2
i = 2 - continue
packages/tmp/looptest: line 14: continue: only meaningful in a `for', `while',
or `until' loop
Loop 2 subshell end
Loop 2 rc 0
loop 3
Loop 3 subshell end
Loop 3 rc 0
loop 4
i = 4 - exit
Loop 4 rc 1
loop 5
Loop 5 subshell end
Loop 5 rc 0

-- 如果我将 shebang 改为:#!/bin/sh
其行为与第一个例子相同 - 除了 - 在我们的机器上,我们专门将 /bin/sh 链接到 bash:

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 9 May 12 22:04 /bin/sh -> /bin/bash

这看起来只是......很奇怪。

这种行为似乎是在最近更新到 Ubuntu 20.04 后开始的。

我意识到可以说新的行为在技术上更正确,但是使用子 shell 来隔离循环之间的变量会非常有帮助,而且这种方法到目前为止仍然有效,这一点令人担忧。

答案1

我没有安装旧的 Ubuntu 或旧的 bash,所以我无法验证这一点。但这个错误修复对我来说似乎是一个很好的解释。

a. Fixed a bug that allowed subshells to "inherit" enclosing loops -- this
   is where POSIX says the subshell is not "enclosed" by the loop.

来源(见第 813 行)

编辑:我无法解释为什么“/bin/sh -> /bin/bash”会产生影响。

相关内容