How can I use jq to sort an array of objects by an IPv4 address value as a 32-bit integer rather than alphanumerically?
An illustration of what I mean with some extra formatting for visual clarity:
$ echo '
{"name": "dns", "ip": "4.4.4.4"}
{"name": "host1", "ip": "10.9.9.9"}
{"name": "host2", "ip": "10.10.10.10"}
' |jq -sr '.|=sort_by(.ip) |.[] |[.name, .ip] |@tsv'
host2 10.10.10.10
host1 10.9.9.9
dns 4.4.4.4
This |=sort_by(.ip)
sorts in alphanumeric order, but I’d like the array sorted "IPnumerically". If I have it in a TSV format like this, I can use external tools (such as this non-POSIX -V
extension to sort
) to do this externally afterward, but is there a way to do this within jq
?
$ echo '
{"name": "dns", "ip": "4.4.4.4"}
{"name": "host1", "ip": "10.9.9.9"}
{"name": "host2", "ip": "10.10.10.10"}
' |jq -sr '.|=sort_by(.ip) |.[] |[.name, .ip] |@tsv' |sort -t$'t' -Vk2
dns 4.4.4.4
host1 10.9.9.9
host2 10.10.10.10
2
Answers
To sort an array of objects by an IPv4 address value as a 32-bit integer using jq, you can convert the IP addresses to integers before sorting. Here’s an example of how you can achieve this:
This will convert each IP address to an array of integers representing the four octets. Then, it calculates the 32-bit integer value by multiplying the respective octets by their corresponding weights and summing them up. Finally, the array is sorted based on the calculated integer values.
The output will be:
Now, the array is sorted "IPnumerically" based on the integer representation of the IP addresses.
Update based on a good comment:
Here’s an updated version of the jq command that sorts the array of objects by IPv4 address value without converting them to a single number:
You can simply split the ip and convert it to an array of numbers:
Full command (note that the reassigning (
.|=
) at the beginning is not needed):