打破循环的 Bash 函数

Ulr*_*rik 4 linux bash loops function break

我做了一个bash function看起来像这样的:

keystroke()
{
    read -s -n1 -t0.1 key     #Read a single keystroke for 0.1 seconds
    [ "$key" = $'\e' ] &&     #If the pressed key is escape
    {
        echo Aborted by user  #Display message
        break                 #Break parent loop
    }
}
Run Code Online (Sandbox Code Playgroud)

每当我需要loop在其他bash函数中优雅地结束 a时,我都会调用 keystroke。我不再能够这样做,因为bashv4.4.0 说:

-bash: break: only meaningful in a `for', `while', or `until' loop
Run Code Online (Sandbox Code Playgroud)

如何在不重复复制相同代码 10 倍以上的情况下解决此问题?

paw*_*moy 5

事实上,似乎从 Bash 4.4 开始,在,或循环break之外不再允许使用关键字。forwhileuntil

我用shenv以下代码段验证了这一点。使用 Bash 4.3.30:

$ shenv shell bash-4.3.30
$ bash -c 'b() { break; }; for i in 1; do echo $i; b; done'
1
Run Code Online (Sandbox Code Playgroud)

使用 Bash 4.4:

$ shenv shell bash-4.4
$ bash -c 'b() { break; }; for i in 1; do echo $i; b; done'
1
environment: line 0: break: only meaningful in a `for', `while', or `until' loop
Run Code Online (Sandbox Code Playgroud)

以及更改日志中的行:https : //github.com/samuelcolvin/bash/blob/a0c0a00fc419b7bc08202a79134fcd5bc0427071/CHANGES#L677

XX。修复了一个错误,该错误可能允许break' or从 shell 函数执行 continue 以影响在函数外运行的循环。

所以现在你不能再break在函数中使用关键字来破坏父循环。解决方案是返回一个状态代码,并在父循环中检查该代码:

keystroke()
{
    read -s -n1 -t0.1 key
    [ "$key" = $'\e' ] &&
    {
        echo Aborted by user
        return 1
    }
}

while true; do
    ...
    keystroke || break
    ...
done
Run Code Online (Sandbox Code Playgroud)

但是,我们可以在更新日志中看到另一个有趣的信息:https : //github.com/samuelcolvin/bash/blob/a0c0a00fc419b7bc08202a79134fcd5bc0427071/CHANGES#L5954

一世。在 POSIX 模式下,break' and如果在 shell 未执行循环时调用,则继续'不会抱怨并返回成功。

因此,如果启用 POSIX 模式,您似乎可以保留旧行为。

$ shenv shell bash-4.4
$ bash --posix -c 'b() { break; }; for i in 1; do echo $i; b; done'
1
Run Code Online (Sandbox Code Playgroud)


hee*_*ayl 2

对于您应该使用的功能return

keystroke() {
    ...
    return
}
Run Code Online (Sandbox Code Playgroud)

可以选择添加一个整数(0 到 127 之间)作为返回值,例如:

keystroke() {
    ...
    return 1
}
Run Code Online (Sandbox Code Playgroud)

请注意,否则将使用最后一个命令的退出状态作为返回值。