my %section; my $hdr_string; # (update: this was intended to be a scalar) while (<>) { next unless ( /\S/ ); # skip blank lines if ( /^\[(.*)\]/ ) { # this is a header line $hdr_string = $1; } else { # this is a data record push @($section{$hdr_string}}, $_; } } # All the lines under a given "header" are now in # the array @{$section{header}}; at this point you can # loop over the sections to manipulate the data records # as appropriate -- e.g.: for my $header ( keys %section ) { for my $rec ( @{$section{$header}} ) { my @recfields = split( /\s+/, $rec ); # ... do whatever is to be done with field data ... } }