my %PCSPLMNCallDataRecords; my $type_name; # type of the block we're reading my $block = undef; # place for block values while ( <> ) { # get each line somehow chomp; # no leading spaces means new block if ( /^PCSPLMNCallDataRecord/ ) { $type_name = undef; # next we expect a type name $block = undef; } # 3 leading spaces signals 'type' of block follows elsif ( /^\s{3}(\S.*)\s+$/ ) { next if ( $typename || $block ); # before we're ready $type_name = $1; # (e.g., 'mSTerminating') $block = {}; # next we expect data } # six leading spaces indicates data line elsif ( /^\s{6}(\S+)\s+(.+)\s*$/ ) { next if (! $typename || ! $block ); # before we're ready # lefthand column is the 'property' name. after first whitespace, # rest is data with trailing whitespace trimmed my ($key, $val) = ($1, $2); # first line in this block if ( scalar keys %$block == 0 ) { # if we don't already have an array create for this type, create one now $PCSPLMNCallDataRecords{$type_name} = [] if not exists $PCSPLMNCallDataRecords{$type_name}; # no values added yet, add hashref to array for this type only for first line push @{$PCSPLMNCallDataRecords{$type_name}}, $block; } $block->{$key} = $val; # add data to block (e.g., 'callIdentificationNumber' => "2487067'D") } } # now you have the following structure in %PCSPLMNCallDataRecords: %PCSPLMNCallDataRecords = ( 'mSTerminating' => [ # array of 'mSTerminating' records { callIdentificationNumber => '2487067\'D', relatedCallNumber => '2487060\'D', recordSequenceNumber => '7410342\'D', exchangeIdentity => '"MAPP01E 0117802"\'S', mSCIdentification => '1119207079800F\'TBCD', cellIDForFirstCellCalled => # etc ... }, { #... next mSTerminating record ... } ], 'mSOtherType' => [ array of 'mSOtherType' records, ... ] ); # an array of hashes with all of the 'mSTerminating' records: my @mSTerminating = @{$PCSPLMNCallDataRecords{mSTerminating}}; # the first 'mSTerminating' record in the array my %mSTerminating = %{$mSTerminating[0]}; # OR my %mSTerminating = %{$PCSPLMNCallDataRecords{mSTerminating}[0]};