【问题标题】:Bash function that breaks loop打破循环的 Bash 函数
【发布时间】:2017-01-08 12:14:35
【问题描述】:

我做了一个bashfunction,看起来像这样:

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 倍的情况下解决此问题?

【问题讨论】:

  • 返回一个由函数调用者检查的状态码?
  • 我在您的代码中看不到任何循环。 mb 这就是为什么?

标签: linux bash function loops break


【解决方案1】:

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

我使用shenv 和以下 sn-p 验证了这一点。使用 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' orcontinue' 的错误 影响在函数外运行的循环的函数。

所以现在你不能再在函数中使用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 模式下,break' andcontinue' 不抱怨返回成功 如果在 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; ...; donekeystroke 在逃生被命中时返回 0,否则返回 1(或更多)。
    • @pawamoy 请阅读 OP 的问题,示例,然后再次阅读我的答案。当您在函数内部时,return 是提早 break 的完美且更可取的方式;函数中是否有常规命令或循环无关紧要。 return 还设置了函数 FYI 的退出状态(就像我提到的那样)。
    • 我已经做到了,但我仍然认为您没有回答 OP 的问题。您的回答仅说明了 return 关键字及其作用。 OP 希望从函数中打破父循环,而不是简单地从函数中提前返回。
    • @pawamoy 如何从函数的调用者可以检查的函数返回状态码?
    猜你喜欢
    • 2012-02-14
    • 2020-06-15
    • 2013-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多