Bash函数以及如何跳出循环

6

我做了一个类似以下代码的 bash 函数:

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
    }
}

每当我需要在其他bash函数中优雅地结束loop时,我只需调用keystroke。自从bash v4.4.0以来,我就无法这样做了,因为它会显示:

-bash: break: only meaningful in a `for', `while', or `until' loop

如何解决这个问题,而不需要重复复制超过10次的代码?


1
返回一个状态码,由函数的调用者进行检查? - Some programmer dude
我在你的代码中没有看到任何循环。可能这就是原因? - deathangel908
2个回答

7

实际上,自从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

使用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

在变更日志中的这行内容:https://github.com/samuelcolvin/bash/blob/a0c0a00fc419b7bc08202a79134fcd5bc0427071/CHANGES#L677

xx. 修复了一个错误,该错误可能会导致从shell函数执行的`break'或`continue'影响到函数外运行的循环。

现在,您不能再使用`break'关键字在函数中终止父循环。解决方法是返回状态码,并在父循环中检查该代码:

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

while true; do
    ...
    keystroke || break
    ...
done

然而,在更改日志中我们可以看到另一个有趣的信息:https://github.com/samuelcolvin/bash/blob/a0c0a00fc419b7bc08202a79134fcd5bc0427071/CHANGES#L5954
在POSIX模式下,breakcontinue不会报错,并且在shell未执行循环时调用时返回成功。因此,如果启用POSIX模式,则似乎可以保留旧的行为。
$ shenv shell bash-4.4
$ bash --posix -c 'b() { break; }; for i in 1; do echo $i; b; done'
1

2

对于函数,您应该使用return

keystroke() {
    ...
    return
}

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

keystroke() {
    ...
    return 1
}

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

它并没有真正回答问题。问题是“如何编写一个函数,让它打破其上层/父循环?”。 显然,在以前的Bash版本中,break在函数中可用,而在Bash >=4.4中不可行。第一条评论是一个好答案:“返回一个状态码,由函数的调用者进行检查”。我想现在没有其他办法了:while true; do keystroke && break; ...; done,当按下 Escape 时,keystroke 返回0,否则返回1(或更多)。 - pawamoy
@pawamoy 请仔细阅读原帖的问题、示例,然后再回来重新阅读我的答案。当你在函数内部时,return 是一种完全正常且更可取的早期退出方式;无论函数中是否有常规命令或循环都没有关系。顺便提一下,return 还设置了函数的退出状态(就像我之前提到的那样)。 - heemayl
我已经做到了,但我仍然认为你没有回答 OP 的问题。你的答案只是讲述了 return 关键字及其作用。OP 想要从函数内部 中断父循环,而不仅仅是从函数早期返回。 - pawamoy
@pawamoy 我该如何从一个函数中返回一个状态码,以便调用该函数的人可以检查它? - heemayl
@pawamoy 不用担心,我不会认为你是针对我说的 :) 如果你觉得你可以做出贡献,你随时都可以添加一个回答。 - heemayl
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接