Reputation: 1141
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?
Upvotes: 6
Views: 4094
Reputation: 3806
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
Upvotes: 7
Reputation: 41987
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.
Upvotes: 2