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' orcontinue' 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' andcontinue' 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