Zyzyx
Zyzyx

Reputation: 524

Perl script running itself with new parameters

I'm working on comparing several lists in order to find mismatches, and figured this would be a good opportunity to put the little bit of Perl experience I've had in the past to use.

My code splits data from two files, allowing me to easily access the data I need (article-numbers and quantities mostly). It then compares these from one file (replacement parts) to another (parts list). However if a Kit is found in the replacement parts list (article numbers starting with K), it will call the same Perl script again but use a list of parts inside the Kit rather than the replacement parts list. After running through the script for the Kit, I hoped it would continue running the original script from where it had called itself.

The problem is that it will first run the script fully (as seen from my output) before starting on running the script for the Kit. Furthermore, the second run of the script (for the Kit) starts halfway through! Skipping creation of the header and most of my data file.

The script takes arguments: partslist.txt replacementparts.txt(or Kitparts) and an optional K as a third argument if it is a Kit. Please excuse me if the script looks messy, I am quite new to this:

#!/usr/bin/perl

use strict;
use warnings;

# quit unless we have the correct number of command-line args
my $num_args = $#ARGV + 1;

if ( $num_args != 2 && $num_args != 3 ) {
    print "$num_args\nUsage: perl perl.pl parts_file.txt replacements_file.txt \(optionally add \"k\" as a third parameter if a Kit\)\n";
    exit;
}

# initialise files
my $file1 = $ARGV[0];
my $file2 = $ARGV[1];

open( my $fh_replacements, "<", $file2 )
        or die "Could not open file '$file2' $!";

open( my $writefile_fh, ">", $writefile )
        or die "Could not open file '$writefile' $!";

# initialise global variables
my $count = 1;
my @splitter;
my @splitter2;

# decide header based on whether we are dealing with a Kit
if ( lc $ARGV[2] ne "k" ) {
    print {$writefile_fh} "File $file2 results:\n\n";
}
else {
    print {$writefile_fh} "\tMontagekit $ARGV[1]:\n";
}

# check the data
while ( my $row = <$fh_replacements> ) {

    if ( $count >= 10 && $row ne "" && $row ne "\n" )
    {    #start at row 10, don't use NULL or newline rows

        my $hits = 0;

        open( my $fh_parts, "<", $file1 ) or die "Couldn't reopen '$file1' $!";

        @splitter = split( '\s*\|\s*', $row );    #split by | with any number of spaces around it

        if ( substr( $splitter[1], 0, 1 ) ne "K" ) {    #check for montageKit

            foreach ( @splitter ) {

                my @line = <$fh_parts>;

                for ( @line ) {

                    $_ =~ s/\x0//g;                     #weird windows64bit related spaces fix

                    if ( $_ =~ /$splitter[1]/ ) {
                        $hits++;
                        $splitter[6] =~ s/\,/\./;
                        @splitter2 = split( /(?<!,)\t/, $_ );    #split by tabs
                    }
                }
            }

            close $fh_parts;

            if ( $hits == 0 ) {
                print {$writefile_fh} "$splitter[1] not matched!\n";
            }    #not found
            elsif ( $hits == 1 ) {    #found

                if ( $splitter[6] == $splitter2[1] ) {
                    print {$writefile_fh} "$splitter[1] matched!\tQuantity match!\n";
                }
                else {
                    print {$writefile_fh} "$splitter[1] matched!\tQuantity mismatch: $splitter[6] - $splitter2[1] \(replacements - parts\)\n";
                }
            }
            else {
                print {$writefile_fh} "$splitter[1] matched $hits times!\n";
            }    #found multiple instances
        }
        else {    #If kit is found, send back to separate instance of program to run for the Kit
            local @ARGV = ( $ARGV[0], $splitter[1] . "\.txt", "k" );
            do 'perl.pl';
        }
    }

    $count++;
}

if ( lc $ARGV[2] ne "k" ) {
    print {$writefile_fh} "\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\n";
}

output:

File 2716576.txt results:

testarticle not matched!
00000126 matched!   Quantity mismatch: 1.0000 - 5 (replacements - parts)
00750020 matched!   Quantity match!
testarticle not matched!
testarticle not matched!
testarticle not matched!
00170018 matched 3 times!
testarticle not matched!
testarticle not matched!
testarticle not matched!
///////////////////
000222 matched! Quantity match!
00050496 matched!   Quantity match!

Only last two lines in the output are from the Kit file.

I imagined this would be better than copy-pasting the same code to run again for the Kit. That is still a last-resort option though if I can't get this to work.

Can anyone tell me where I'm going wrong? I feel like some variables are carrying over, and/or that the second run of the script doesn't start where I'd like it to. I'm not sure how to fix that though, I've tried all the troubleshooting I could muster so any help would be greatly appreciated.

Upvotes: 1

Views: 260

Answers (1)

BOC
BOC

Reputation: 1139

I think you just need to declare a subroutine that can be called recursively.

#!/usr/bin/perl
use strict;
use warnings;

# quit unless we have the correct number of command-line args
my $num_args = $#ARGV + 1;
if ($num_args != 2 && $num_args != 3) {
    print "$num_args\nUsage: perl perl.pl parts_file.txt replacements_file.txt \(optionally add \"k\" as a third parameter if a Kit\)\n";
    exit;
}

process_kit (@ARGV);

sub process_kit {
    my ($file1, $file2, $argv2) = @_;

    open( my $fh_replacements, "<", $file2 )    
        or die "Could not open file '$file2' $!"; 
    open( my $writefile_fh, ">", $writefile )
        or die "Could not open file '$writefile' $!";

# initialise local variables
    my $count = 1;
    my @splitter;
    my @splitter2;

# decide header based on whether we are dealing with a Kit
    if (lc $argv2 ne "k") { 
        print {$writefile_fh} "File $file2 results:\n\n";} 
    else { 
        print {$writefile_fh} "\tMontagekit $ARGV[1]:\n";}
# check the data
    while ( my $row = <$fh_replacements> ) {
        if ( $count >= 10 && $row ne "" && $row ne "\n" ) {  #start at row 10, don't use NULL or newline rows
            my $hits = 0;
            open( my $fh_parts, "<", $file1 ) or die "Couldn't reopen '$file1' $!";
            @splitter = split( '\s*\|\s*', $row );    #split by | with any number of spaces around it
            if (substr($splitter[1],0,1) ne "K") {    #check for montageKit
                foreach (@splitter) {
                    my @line = <$fh_parts>;
                    for (@line) {
                        $_ =~ s/\x0//g;    #weird windows64bit related spaces fix
                        if ( $_ =~ /$splitter[1]/ ) {
                            $hits++;
                            $splitter[6] =~ s/\,/\./;
                            @splitter2 = split( /(?<!,)\t/, $_ );    #split by tabs
                        }
                    }
                }
                close $fh_parts;
                if ( $hits == 0 ) { print {$writefile_fh} "$splitter[1] not matched!\n"; }  #not found
                elsif ( $hits == 1 ) {                                                      #found  
                    if ( $splitter[6] == $splitter2[1] ) {
                        print {$writefile_fh} "$splitter[1] matched!\tQuantity match!\n";
                    }
                    else {
                        print {$writefile_fh} 
                        "$splitter[1] matched!\tQuantity mismatch: $splitter[6] - $splitter2[1] \(replacements - parts\)\n";
                    }
                }
                else { print {$writefile_fh} "$splitter[1] matched $hits times!\n"; }           #found multiple instances
            }
            else {   #If kit is found,run again the program for the Kit
                process_kit($file1, $splitter[1]."\.txt", "k");
            }
        }

        $count++;
    }
    if (lc $argv ne "k") { print {$writefile_fh} "\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\n";}
}

Upvotes: 2

Related Questions