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.
CodePudding user response:
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 whiles 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})
