in reply to nesting loops help?

You really need to use strict (use strict;). Consider what happens when the following line invokes the die.

open my $wave, '>', 'Wave' or die "Can't open $wave: $!";

Using three parameter open and error handling is laudatory, but omitting strict and a few other areas of your code could use some TLC. Consider the following light do over:

#!usr/bin/perl use strict; use warnings; open my $wave, '>', 'Wave' or die "Can't open 'Wave': $! +"; open my $keywords, '<', 'Agents' or die "Can't open 'Agents': +$!"; open my $search_file, '<', 'Definitions' or die "Can't open 'Definitio +ns': $!"; my $keyword_or = join '|', map {chomp; qr/\Q$_\E/} <$keywords>; my $regex = qr|\b($keyword_or)\b|; while (defined (my $line = <$search_file>)) { while ($line =~ /$regex/g) { next if $line =~ /(SCRIPTNAME|DESCRIPTION)/; print $wave $line; last; } }

Things to note:

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

Replies are listed 'Best First'.
Re^2: nesting loops help?
by shadowfox (Beadle) on Mar 10, 2022 at 16:47 UTC
    Thanks! I really appreciate the break down of improvements, trying to do better I just don't always understand the suggestions and as a bad habit sometimes I turn off strict until I get something working then go back and polish it, a lot room for improvement still.

    If you have a moment I've run into a desire to join the script you helped with to another that's similar, I'm not following the logic of how to iterate over multiple sources very well. I'll repost what I'm using now for example. In the first script that you helped with it takes a value from $search file to see if its in the $schedule file that's read into a hash at the beginning, which is great thanks to your your help.

    I have another function which was done separately because I generally find doing tasks in smaller chunks easier to understand and get right, but I'd like to bring them together, this one reads $schedule line by line, when it matches a regex pattern it pushes that value into an array, when it reaches the value from the $search_file, I have it print the last value stored in the array, because its not the $search_file value I need next, its actually a value several lines above it that I captured with regex so this is kind of a look behind procedure?

    Basically my confusion hit turbulence trying to do both, does it make sense to then change the first script to iterate line by line instead before trying to pair them, or is there a way to still do the regex capture if I'm instead using the existing hash already saved in the first script?
    use warnings; use strict; open my $schedule, '<', 'Schedule'; my %schedule; $schedule{$_} = 1 while (<$schedule>); close $schedule; open my $wave, '>', 'Wave' or die "Can't open 'Wave': $! +"; open my $keywords, '<', 'Agents' or die "Can't open 'Agents': +$!"; open my $search_file, '<', 'Definitions' or die "Can't open 'Definitio +ns': $!"; my $keyword_or = join '|', map {chomp; qr/\Q$_\E/} <$keywords>; my $regex = qr|\b($keyword_or)\b|; open my $schedule, '<', 'Schedule' or die "Can't open 'Schedule': $!"; while (defined (my $line = <$search_file>)) { while ($line =~ /$regex/g) { next if $line =~ /(SCRIPTNAME|DESCRIPTION)/; my $lineout = $line; chomp $lineout; print $wave $lineout; print $wave exists $schedule{$line} ? " | Yes \n" : " | No +\n"; print $wave exists $schedule{$line} ? " | Yes \n" : " | No +\n"; # at this point my output looks something like this: VALUE_FRO +M_SEARCH_FILE | Yes # want to use the value in $line as the input variable to the +other script where marked as $value_from_line_in_search_file # want to print the result of other script back here # at this point I would like the output like this: VALUE_FROM_ +SEARCH_FILE | Yes | VALUE_FROM_SCHEDULE_FILE last; } }
    use warnings; use strict; my $value_from_line_in_search_file = 'SAMPLE#DATA'; open my $schedule, '<', 'Schedule' or die "Can't open 'Schedule': $!"; my @values=(); while (<$schedule>) { if (/(^SCHEDULE)(.*)/) { # SCHEDULE SCHEDULENAME, I only want the na +me. push(@values, $2); } if (/$value_from_line_in_search_file/) { print $values[-1]; last; } }

      I always start with strictures on and never turn them off. At the very least my editor then warns me about typos and variables that are either out of scope or haven't been declared yet. Having that heads up before you run the code generally saves a few debugging iterations straight off the bat!

      At this point some sample data would help a lot. You can include it in a short self contained example script like this:

      use warnings; use strict; my $scheduleData = <<SDATA; Person 1: Joe SDATA my $agentData = <<ADATA; Joe Moe Flo ADATA my $defsData = <<DDATA; SCRIPTNAME It's a wonderful life Person 1: Joe Person 2: Moe DDATA open my $schdIn, '<', \$scheduleData or die "Can't open 'Schedule': $! +"; my %scheduleMatch = map {chomp; $_ => 1} <$schdIn>; open my $agentsIn, '<', \$agentData or die "Can't open 'Agents': $!"; open my $defsIn, '<', \$defsData or die "Can't open 'Definitions': +$!"; my $agentsList = join '|', map {chomp; qr/\Q$_\E/} <$agentsIn>; my $agentsMatch = qr|\b($agentsList)\b|; while (defined(my $defLine = <$defsIn>)) { chomp $defLine; if ($defLine =~ $agentsMatch && $defLine !~ /(SCRIPTNAME|DESCRIPTI +ON)/) { my $lineout = $defLine; my $flag = $scheduleMatch{$defLine} ? 'Yes' : 'No'; print "$defLine | $flag\n"; } }

      which prints:

      Person 1: Joe | Yes Person 2: Moe | No

      Then tell us where the test script doesn't work as expected or, in this case, how the output should look for the additional functionality you want.

      Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
        use warnings; use strict; open my $schedule, '<', 'Schedule'; my %schedule; $schedule{$_} = 1 while (<$schedule>); close $schedule; open my $wave, '>', 'Wave' or die "Can't open 'Wave': $! +"; open my $keywords, '<', 'Agents' or die "Can't open 'Agents': +$!"; open my $search_file, '<', 'Definitions' or die "Can't open 'Definitio +ns': $!"; my $scheduleData = <<SDATA; SCHEDULE OTHER_NAME DONTCARE NOTIMPORTANT : MNDJWIEL#DIFFERENTDATA OTHERDATA NOTIMPORTANT END SCHEDULE NAME_I_WANT DONTCARE NOTIMPORTANT : MNDJWIEL#OTHERDATA OTHERDATA NOTIMPORTANT END SDATA my $agentData = <<ADATA; HSJEKDIE MNDJWIEL NSKQI OIFNHDU H3KID ADATA my $defsData = <<DDATA; MNDJWIEL#OTHERDATA SCRIPTNAME "JKASDHAJSDHAKJDAS.cmd" DESCRIPTION "NOTIMPORTANT" OIFNHDU#UNIMPORTANT SCRIPTNAME "JKASDHAJSDHAKJDAS.cmd" DESCRIPTION "SOMETIMES HAS AGENTNAME OIFNHDU" NSKQI#SOMETHINGHERE SCRIPTNAME "JKASDHAJSDHAKJDAS.cmd" DESCRIPTION "NOTIMPORTANT" HSJEKDIE#DOESNTMATTER SCRIPTNAME "SOMETIMES HAS AGENTNAME HSJEKDIE" DESCRIPTION "NOTIMPORTANT" DDATA open my $schdIn, '<', \$scheduleData or die "Can't open 'Schedule': $! +"; my %scheduleMatch = map {chomp; $_ => 1} <$schdIn>; open my $agentsIn, '<', \$agentData or die "Can't open 'Agents': $!"; open my $defsIn, '<', \$defsData or die "Can't open 'Definitions': +$!"; my $agentsList = join '|', map {chomp; qr/\Q$_\E/} <$agentsIn>; my $agentsMatch = qr|\b($agentsList)\b|; while (defined(my $defLine = <$defsIn>)) { chomp $defLine; if ($defLine =~ $agentsMatch && $defLine !~ /(SCRIPTNAME|DESCRIPTI +ON)/) { my $lineout = $defLine; my $flag = $scheduleMatch{$defLine} ? 'Yes' : 'No'; print "$defLine | $flag\n"; } }
        Which prints this, because the example has only 1 of the below values from DDATA that's also in SDATA:
        MNDJWIEL#OTHERDATA | Yes OIFNHDU#UNIMPORTANT | No NSKQI#SOMETHINGHERE | No HSJEKDIE#DOESNTMATTER | No
        From this point I'd like to use the look behind method to make the data this
        MNDJWIEL#OTHERDATA | Yes | NAME_I_WANT OIFNHDU#UNIMPORTANT | No | Missing NSKQI#SOMETHINGHERE | No | Missing HSJEKDIE#DOESNTMATTER | No | Missing
        Which I can do via two separate scripts, but obviously it would be more efficient to join the functionality.
        use warnings; use strict; my $scheduleData = <<SDATA; SCHEDULE OTHER_NAME DONTCARE NOTIMPORTANT : MNDJWIEL#DIFFERENTDATA OTHERDATA NOTIMPORTANT END SCHEDULE NAME_I_WANT DONTCARE NOTIMPORTANT : MNDJWIEL#OTHERDATA OTHERDATA NOTIMPORTANT END SDATA my $defLine = 'MNDJWIEL#OTHERDATA'; open my $schdIn, '<', \$scheduleData or die "Can't open 'Schedule': $! +"; my @values=(); while (<$schdIn>) { if (/(^SCHEDULE)(.*)/) { # SCHEDULE SCHEDULENAME, I only want the na +me. push(@values, $2); } if (/$defLine/) { print $values[-1]; last; } }
        Which prints:
        NAME_I_WANT
        I will say that at first I didn't see the point in adding sample data but I kind of get it now, seeing what I'm trying to get from the data helps convey desired functionality that I may not be good at explaining.