Reputation: 2301
In a script I'm writing, I try to exit out of the second nested while loop, and the continue statement appears to be simply ignored, and I'm unsure of exactly why.
From the manual:
continue [n]:
Resume the next iteration of the enclosing for, while, until, or select loop. If n is specified,
resume at the nth enclosing loop. n must be ≥ 1. If n is greater than the number of enclosing
loops, the last enclosing loop (the ``top-level'' loop) is resumed. The return value is 0 unless n
is not greater than or equal to 1.
A minimal example that illustrates my problem (ex1.sh
):
#!/bin/bash
printf "%d\n" {1..3} | while read i; do
printf "%d\n" {1..3} | while read j; do
sum=$(expr $i + $j)
echo "$i + $j = $sum"
[ $sum -ge 5 ] && echo continue && continue 2
done
echo 'should only see this for first cycle of i (2+3 >= 5)'
done
Output of ex1.sh
:
1 + 1 = 2
1 + 2 = 3
1 + 3 = 4
should only see this for first cycle of i (2+3 >= 5)
2 + 1 = 3
2 + 2 = 4
2 + 3 = 5
continue
should only see this for first cycle of i (2+3 >= 5)
3 + 1 = 4
3 + 2 = 5
continue
3 + 3 = 6
continue
should only see this for first cycle of i (2+3 >= 5)
Why is the continue 2
ignored? It clearly echos out "continue", and the fact that continue runs is confirmed by running a trace with set -x
The use of printf
is obviously silly ex1.sh
, but reproduces the issue I'm having with getting continue to work in a while read x...
loop.
A for loop works as expected (ex2.sh
):
#!/bin/bash
for i in {1..3}; do
for j in {1..3}; do
sum=$(expr $i + $j)
echo "$i + $j = $sum"
[ $sum -ge 5 ] && echo continue && continue 2
done
echo 'should only see this for first cycle of i (2+3 >= 5)'
done
Output of ex2.sh
:
1 + 1 = 2
1 + 2 = 3
1 + 3 = 4
should only see this for first cycle of i (2+3 >= 5)
2 + 1 = 3
2 + 2 = 4
2 + 3 = 5
continue
3 + 1 = 4
3 + 2 = 5
continue
So, why does ex1.sh
seem to ignore the continue 2
builtin, whereas ex2.sh
behaves as expected?
Fixed the first example myself thanks to M. Nejat Aydin:
#!/bin/bash
while read i; do
while read j; do
sum=$(expr $i + $j)
echo "$i + $j = $sum"
[ $sum -ge 5 ] && echo continue && continue 2
done < <(printf "%d\n" {1..3})
echo 'should only see this for first cycle of i (2+3 >= 5)'
done < <(printf "%d\n" {1..3})
The issue is that pipelines create subshells, so my continue statement was behaving as expected according to the manual, continuing at the outermost loop that subshell was aware of.
Upvotes: 2
Views: 362
Reputation: 10123
Your while
loops are not nested. They're running in different subshells. continue
cannot continue from the parent shell. A pipe (|
) creates a subshell. On the other hand, the version below should work as expected because both while
s are running in the same shell:
while read i; do
while read j; do
sum=$(expr $i + $j)
echo "$i + $j = $sum"
[ $sum -ge 5 ] && echo continue && continue 2
done < <(printf "%d\n" {1..3})
echo 'should only see this for first cycle of i (2+3 >= 5)'
done < <(printf "%d\n" {1..3})
Upvotes: 3