in reply to lost in my data structure.

If you never have anything besides "tcp" under "ip1" (or "ip2", etc), then "tcp" represents an unnecessary layer in the structure -- based on the sample data you show, the top-level keys could just as well be "ip1.tcp", "ip2.tcp", etc.

Anyway, something like this would produce the output format you suggested:

for my $ip ( sort keys %host ) { print "$ip\n"; for my $proto ( sort keys %{$host{$ip}} ) { # assuming there will +be keys other than "tcp" for my $port ( sort {$a<=>$b} keys %{$host{$ip}{$proto}} ) { printf( "%3d\t%s\t%s\n", $port, $host{$ip}{$proto}{$port}{state}, $host{$ip}{$proto}{$port}{service} ); } } }
Note how the curly braces are placed around  $host{$ip} and then also around  $host{$ip}{$proto} so that these hash values (which happen to be a references to another hash) can be dereferenced for use with the "keys" function -- the "%" outside of those exta curlies tells perl to pass the entire dereferenced hash to "keys".