1

I have an array in my script which I want to use it in for, like this:

for j in "${list[@]}"
do
    func $j
done

In function func, sometimes another member will add to the list array, but the for iterates as many time as it was initiated(before the for started)
I want "for" to iterate based on the updated array content

some lines of that function:

if [ $s1 -gt 0 ]
then
   (( k = $k +1 ))
    list[$k]=$id2
fi
3
  • 3
    It is always pretty tricky to iterate over a list and modify the list at the same time. I would definitely suggest trying to think if there is another way to accomplish what you're doing. If this is the right approach for you though, you could probably find a way to use a while loop to keep the going and track where you are in the list, and possibly have it update the stop condition during iteration Commented Jul 25, 2015 at 12:11
  • given that your storing $k you could change the loop until $k instead of the in clause Commented Jul 25, 2015 at 12:28
  • Don't forget to quote "$j" on the line that passes it to func. You don't want the shell treating the contents of the variable as code. (word-splitting on whitespace) Commented Jul 25, 2015 at 18:34

2 Answers 2

6

As Eric Renouf said, modifying the list you're working on can be tricky. As long as you're only appending new elements (to the end of the list), and just want those new elements included in the iteration, you can use something like this:

for ((i=0; i<${#list[@]}; i++)); do
    #...
    if (( s1 > 0 )); then
        list+=( "$id2" )
    fi
done

Since the length of the list (${#list[@]}) is recalculated every time around, the loop will include new elements. Also, the +=( ) syntax guarantees you're always strictly appending.

Sign up to request clarification or add additional context in comments.

4 Comments

You didn't specifically explain that for works by expanding the list to iterate over when it first runs, not once per iteration. It's not iterating over the list per-se, it's iterating over that one expansion of "${list[@]}" which is done before the first loop iteration. So it's not just the number of iterations, but also the values that $j will take, which are fixed.
@PeterCordes It never actually expands the entire list; ${#list[@]} (note the #) is just the current length of the list, so the for loop runs until it gets to the (current) end of the list.
Sorry, I wasn't talking about your code, I was talking about the other kind of for loop: for var in "${list[@]}". The way the OP phrased his description ("the for iterates as many time as it was initiated") made me want to point out what I did in my comment.
@PeterCordes Ah, in that case you're completely correct.
1

It appears that k is the index of the last element, meaning your function only appends items to the end of the list. It seems the best option is to iterate while a separate counter is less than k.

i=0
while (( i < k )); do
    j=${list[i]}
    func "$j"
    ((i++))
done

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.