jsonsortingjqipv4

How can I sort by IP address in jq?


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

Solution

  • You can simply split the ip and convert it to an array of numbers:

    sort_by(.ip | split(".")[] | tonumber)
    

    Full command (note that the reassigning (.|=) at the beginning is not needed):

    $ 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 | split(".")[] | tonumber) | .[] | [.name, .ip] | @tsv'
    
    dns 4.4.4.4
    host1   10.9.9.9
    host2   10.10.10.10