Blah Blah Woof Woof

Archived content 2005-2007

Evenly dividing array elements in bash

Posted by Tim Riley Tue, 27 Mar 2007 20:08:00 GMT

Writing in bash is fun because of the constraints it offers, but I’m never sure if I am choosing the most straightforward way to do things.

A few weeks ago I had to write a script to vacuum a bunch of databases once per week. Instead of doing them all at once, I wanted to evenly spread the load across the seven days.

I wrote something that works pretty well, I think, but it does seem a little hackish, and I’d love to hear if there is a better way to achieve this.

Here’s what I did, check it out:

 # 11 elements in this example
 # Should be processed 2 per day for the first 4 days, then 1 per day for the reamining 3 days
 items=("mario" "luigi" "toad" "peach" "yoshi" "wario" "koopa" "bowser" "lakitu" "birdo" "fryguy")

 days=7

 # number of the current day, starting from 0
 let "today = `date +%u` - 1" 

 # number of whole that can be processed per day
 let "per_day = ${#items[*]} / ${days}" 

 # remainder of items that must also be processed
 let "remainder = ${#items[*]} % ${days}" 

 # index of array element to start iterating from for the current day
 if [ $today -gt $remainder ]; then
   let "start = (${per_day} * ${today}) + ${remainder}" 
 else
   let "start = (${per_day} * ${today}) + ${today}" 
 fi

 # number of elements to iterate over for the current day
 if [ $today -ge $remainder ]; then
   count=$per_day
 else
   let "count = ${per_day} + 1" 
 fi

 # Do it!
 echo "Processing ${count} items." 

 for ((i=$start; i < ($start+$count); i++)); do
   do_something_with_item ${items[$i]}
 done

If you can offer any tips or suggestions, please comment on this entry!

Comments

  1. Vidar Bashman Madsen said 1 day later:
    Lacking a preview option and no info on tags, I hope this is formatted properly... How about this approach; Iterate through the items, if item_number % days = today, process item. The code:
    
     i=0
     for item in ${items[@]}; do
       if [ $[$i % $days] = $today ]; then
         echo "Process $item..."
       fi
       i=$[$i+1]
     done
    

(leave url/email »)