my %seen; my %tree; while (<>) { chomp; # change this to match, as you didn't give a good example my ($file,$line,$rule) = m/^"(.*?)"\s*(\d+):\s*[^:]*?:\s*(\d+):/; unless ( exists( $seen{"$file,$line,$rule"} ) { push @{$seen{"$file,$line,$rule"}}, $file,$line,$rule; $tree{$rule}{$file}{$line} = 1; } }