I made a bash
function
that looks something like this:
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
}
}
And whenever I needed to gracefully end a loop
in other bash
functions, i just called keystroke. I am no longer able to do this since bash
v4.4.0 says:
-bash: break: only meaningful in a `for', `while', or `until' loop
How can I solve this without copying the same code over and over again more than 10x?
Indeed it seems that since Bash 4.4, the break
keyword is not allowed anymore outside of a for
, while
or until
loop.
I verified this with shenv
and the following snippet. With Bash 4.3.30:
$ shenv shell bash-4.3.30
$ bash -c 'b() { break; }; for i in 1; do echo $i; b; done'
1
And with 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
And the line in the changelog: https://github.com/samuelcolvin/bash/blob/a0c0a00fc419b7bc08202a79134fcd5bc0427071/CHANGES#L677.
xx. Fixed a bug that could allow
break' or
continue' executed from shell functions to affect loops running outside of the function.
So now you cannot use the break
keyword in a function anymore to break the parent loop. The solution is to return a status code instead, and check that code in the parent loop:
keystroke()
{
read -s -n1 -t0.1 key
[ "$key" = $'\e' ] &&
{
echo Aborted by user
return 1
}
}
while true; do
...
keystroke || break
...
done
However, we can see in the changelog another interesting information: https://github.com/samuelcolvin/bash/blob/a0c0a00fc419b7bc08202a79134fcd5bc0427071/CHANGES#L5954.
i. In POSIX mode,
break' and
continue' do not complain and return success if called when the shell is not executing a loop.
So it seems you can retain the old behavior if you enable POSIX-mode.
$ shenv shell bash-4.4
$ bash --posix -c 'b() { break; }; for i in 1; do echo $i; b; done'
1
For functions you should use return
:
keystroke() {
...
return
}
Optionally add an integer (between 0 and 127) as the return value e.g.:
keystroke() {
...
return 1
}
Note that, otherwise the exit status of the last command will be used as the return value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With