in reply to Unable to get the paragraph in the list of hashes. Getting single lines instead.

Perhaps:

use strict; use warnings; use Data::Dumper; my %records; local $/ = "\n\n"; while (<DATA>) { next if !/^(\d+):(.*)/s; $records{$1} = $2; } print Dumper(\%records); __DATA__ Storage system address: 192.168.1.2 Storage system port: 443 HTTPS connection 1: ID = disk_dpe_0_0 Enclosure = DPE_0 Slot = 0 Name = DPE Disk 0 Health state = OK (5) Health details = "The component is operating normally. No ac +tion is require +d." Type = SAS Capacity = 288196762624 (268.4G) Rotational speed = 15000 rpm User capacity = 236420176896 (220.2G) Pool = performance Current speed = 6 Gbps Maximum speed = 6 Gbps Manufacturer = SEAGATE Model = STE30065 CLAR300 Vendor capacity = 322122547200 (300.0G) Part number = 005049273 Serial number = 6SJ2C6MV Firmware revision = ES0E WWN = 06:00:00:00:05:00:00:00:00:00:00:00:00:00:00 +:03 2: ID = disk_dpe_0_1 Enclosure = DPE_0 Slot = 1 Name = DPE Disk 1 Health state = OK (5) Health details = "The component is operating normally. No ac +tion is require +d." Type = SAS Capacity = 288196762624 (268.4G) Rotational speed = 15000 rpm User capacity = 236420176896 (220.2G) Pool = performance Current speed = 6 Gbps Maximum speed = 6 Gbps Manufacturer = SEAGATE Model = STE30065 CLAR300 Vendor capacity = 322122547200 (300.0G) Part number = 005049273 Serial number = 6SJ28QF3 Firmware revision = ES0E WWN = 06:00:00:00:05:00:00:00:01:00:00:00:01:00:00 +:03

Prints:

$VAR1 = { '1' => ' ID = disk_dpe_0_0 Enclosure = DPE_0 Slot = 0 Name = DPE Disk 0 Health state = OK (5) Health details = "The component is operating normally. No ac +tion is required." Type = SAS Capacity = 288196762624 (268.4G) Rotational speed = 15000 rpm User capacity = 236420176896 (220.2G) Pool = performance Current speed = 6 Gbps Maximum speed = 6 Gbps Manufacturer = SEAGATE Model = STE30065 CLAR300 Vendor capacity = 322122547200 (300.0G) Part number = 005049273 Serial number = 6SJ2C6MV Firmware revision = ES0E WWN = 06:00:00:00:05:00:00:00:00:00:00:00:00:00:00 +:03 ', '2' => ' ID = disk_dpe_0_1 Enclosure = DPE_0 Slot = 1 Name = DPE Disk 1 Health state = OK (5) Health details = "The component is operating normally. No ac +tion is required." Type = SAS Capacity = 288196762624 (268.4G) Rotational speed = 15000 rpm User capacity = 236420176896 (220.2G) Pool = performance Current speed = 6 Gbps Maximum speed = 6 Gbps Manufacturer = SEAGATE Model = STE30065 CLAR300 Vendor capacity = 322122547200 (300.0G) Part number = 005049273 Serial number = 6SJ28QF3 Firmware revision = ES0E WWN = 06:00:00:00:05:00:00:00:01:00:00:00:01:00:00 +:03 ' };

Note the use of local $/ = "\n\n"; to turn the line break "character" (record separator) into two line breaks as an easy way of reading the input as a stream of records.

Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond

Replies are listed 'Best First'.
Re^2: Unable to get the paragraph in the list of hashes. Getting single lines instead.
by pritesh_ugrankar (Monk) on Sep 20, 2020 at 21:43 UTC

    Hi GrandFather,

    Thank you very much for taking time to try this out and suggestion a truly genius solution. However, I was looking more for something that would let me access each field as a value so that I could get something like so (note that the output below does not :

    { '1: ID' => 'disk_dpe_0_0', 'Capacity' => '576393510912 (536.8G)', 'Rotational speed' => '15000 rpm', #more similar stuff............. 'User capacity' => '576359956480 (536.8G)', 'Pool' => 'Hot Spare (not in use)', }, #and so on....

    That way, I could only extract the values of a few keys and not the entire hash. But, you've already done a lot. Let me try something and come back here in case I cannot do it. Thank you once again Sir.

      You can break out the record fields by processing the record string as a list of lines:

      use strict; use warnings; use Data::Dumper; my %records; local $/ = "\n\n"; while (<DATA>) { next if !/^(\d+):(.*)/s; my ($id, $tail) = ($1, $2); local $/ = "\n"; open my $recIn, '<', \$tail; while (<$recIn>) { chomp; #next if !/(\w+)\s*=\s*(.*)/; # #$records{$id}{$1} = $2; next if !/^\s*?([^=]+)\s*=\s*(.*)/; my ($key, $value) = ($1, $2); s/^\s+|\s+$//g for $key, $value; $records{$id}{$key} = $value; } } print Dumper(\%records); __DATA__ ...

      Using the previous data prints:

      $VAR1 = { '1' => { 'Capacity' => '288196762624 (268.4G)', 'WWN' => '06:00:00:00:05:00:00:00:00:00:00:00:00:00 +:00:03', 'Pool' => 'performance', 'Model' => 'STE30065 CLAR300', 'Maximum speed' => '6 Gbps', 'Health details' => '"The component is operating no +rmally. No action is required."', 'Vendor capacity' => '322122547200 (300.0G)', 'Part number' => '005049273', 'Enclosure' => 'DPE_0', 'Health state' => 'OK (5)', 'Serial number' => '6SJ2C6MV', 'Slot' => '0', 'Type' => 'SAS', 'User capacity' => '236420176896 (220.2G)', 'ID' => 'disk_dpe_0_0', 'Manufacturer' => 'SEAGATE', 'Name' => 'DPE Disk 0', 'Current speed' => '6 Gbps', 'Rotational speed' => '15000 rpm', 'Firmware revision' => 'ES0E' }, '2' => { 'WWN' => '06:00:00:00:05:00:00:00:01:00:00:00:01:00 +:00:03', 'Pool' => 'performance', 'Capacity' => '288196762624 (268.4G)', 'Slot' => '1', 'Serial number' => '6SJ28QF3', 'Health state' => 'OK (5)', 'Part number' => '005049273', 'Enclosure' => 'DPE_0', 'Model' => 'STE30065 CLAR300', 'Maximum speed' => '6 Gbps', 'Health details' => '"The component is operating no +rmally. No action is required."', 'Vendor capacity' => '322122547200 (300.0G)', 'ID' => 'disk_dpe_0_1', 'User capacity' => '236420176896 (220.2G)', 'Manufacturer' => 'SEAGATE', 'Type' => 'SAS', 'Rotational speed' => '15000 rpm', 'Firmware revision' => 'ES0E', 'Current speed' => '6 Gbps', 'Name' => 'DPE Disk 1' } };

      Note that local overrides the variable's value just for the current block so changing $/ inside the main loop doesn't affect while (<DATA>). open my $recIn, '<', \$tail; treats $tail as a file.

      Update: Replaced commented out code to fix the single word matches for keys issue caught by tybalt89.

      Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond

        This only gets the last word of multi-word keys - i.e. "speed" - when there are three different "speeds" in the data.

        Hi,

        Sorry for the late reply. Just logged in after work. This is awesome!!. Truly a genius solution!!. There's a lot I've learnt from your code.

        Just so that I get it right, when you say next if !/^(\d+):(.*)/s; it means, just move next if you find a line that starts with one or more digits, followed by a colon, and then some stuff. I am not sure what the /s does though, does it mean "spill" this regex over even if there is a new line?

        Further down, the next if !/^\s*?([^=]+)\s*=\s*(.*)/ I guess means

        next if ! -> Move to the next line if the line does NOT / ^\s*? -> begin with one or more space (? makes this lazy I guess) ([^=]+)-> Does not include the literal "equal to" sign & create captur +e group of whatever text is there. \s* -> Some more space. = -> Literal "equal to" \s* -> Some more space. (.*) -> Second capture group of the remaining stuff. /

        Please let me know if my understanding is right.

        The lines  my ($id, $tail) = ($1, $2) and the entire code in the second while loop is simply amazing and an eye opener!! I have no words to express my gratitude for showing this amazing stuff!!