I hit a problem the other day where I needed to iterate over a range of IPv4 addresses in a bash script. I’d often just do it in perl, but it often feels tidier to do it all in the bash script, so that’s what I was aiming for.

The method I came up with is to convert the start and end IP addresses into integers, then loop from one to another, converting back to IP addresses. This is all fairly straightforward maths, so easy enough to do in bash.

First, a function to convert from an IP address to an integer. I guess it may be faster to use bash’s $(()) syntax here rather than expr.

function ip_to_int()
  local IP="$1"
  local A=`echo $IP | cut -d. -f1`
  local B=`echo $IP | cut -d. -f2`
  local C=`echo $IP | cut -d. -f3`
  local D=`echo $IP | cut -d. -f4`
  local INT

  INT=`expr 256 "*" 256 "*" 256 "*" $A`
  INT=`expr 256 "*" 256 "*" $B + $INT`
  INT=`expr 256 "*" $C + $INT`
  INT=`expr $D + $INT`

  echo $INT

Then convert from an integer back to an IP address again.

function int_to_ip()
  local INT="$1"

  local D=`expr $INT % 256`
  local C=`expr '(' $INT - $D ')' / 256 % 256`
  local B=`expr '(' $INT - $C - $D ')' / 65536 % 256`
  local A=`expr '(' $INT - $B - $C - $D ')' / 16777216 % 256`

  echo "$A.$B.$C.$D"

From then it’s just a case of converting the beginning and end IPs into integers for the loop, and converting back inside the loop.


for INT in `seq $S 1 $E`
  IP=`int_to_ip $INT`
  # do something with $IP here

It may not be the most efficient method, but it’s fine for a script that generally runs just once at startup and adds traffic control ratelimits for the IPs.

3 Thoughts on “Iterating over a range of IP addresses in bash”

  • The problem here is that you shouldn’t be iterating over IP addresses at all. It only works for Legacy IP, and doesn’t scale to a whole IPv6 /64 subnet. The lack of IPv6 support here isn’t just an implementation issue — it’s a *design* issue.You’re not going to iterate over all 2⁶⁴ addresses in a subnet, right?So whatever you’re doing, it would be better if we had some way of doing that per-subnet instead of per-IP.. If we really *must* do it per-IP, then perhaps we’d have to do it when each IP address is first detected (hooked into ARP or ND on the router perhaps). After all, its traffic control limit doesn’t matter while it’s not sending or receiving *any* traffic.I’m sure you’re trying to be helpful by posting the script here, in case anyone else feels the need to iterate over IP addresses. But you’re leading the horse to a watering hole that’s tainted. If it causes someone to use your script when instead they might have done something that *doesn’t* iterate over IP addreses, then you have perhaps done them a disservice by leading them into an obsolete design.This being the year that we expect the Legacy IP address allocations to be exhausted, and the laggards really *have* to catch up and start deploying IPv6, we really shouldn’t be deploying anything new that has real design issues being ported to IPv6.

  • I agree with all that, and at some point will have to rewrite it, at least for IPv6, even if the IPv4 stuff stays the same. At the moment I’m trying to get an enterprise wireless network up and running quickly, which means a) IPv4 and b) static configuration built by the above, rather than dynamic configs. I probably should have made this clear in the initial post.The plan is that later on in the year I’ll start testing IPv6 on this network. However, I understand that there are still issues with IPv6 on Cisco wireless networks, which means that, as much as I’d love to roll it out from the start, it’s going to have to wait a while. While I’m waiting, I can start to plan and test how I’ll dynamically add and remove rules for each IP address as it’s seen – like you say, maybe looking at ARP/ND, or by using Argus traffic logs to see when IPs were used last.In some way it’s a shame that there is no tc way to do ‘traffic shaping for each IP in this range’, but that’s pushing stuff into the kernel that probably needn’t be.My guess, however, is that at least initially we’ll run with traffic shaping on IPv4, and none on IPv6 — if nothing else it’s an incentive for people to use IPv6 over IPv4 where possible!

  • I’ve also seen problems with IPv6 on Cisco wireless networks. In my case it turned out the network was breaking *all* multicast traffic. If Neighbour Discovery isn’t working, nothing much else is going to work…I’ve never dealt with Cisco crap and *not* had a painful experience, in fact.

Leave a Reply

Your email address will not be published. Required fields are marked *