-2

The propose of the script to grep some value from some data table in the ASCII files.

datatable

I modified the script which I posted yesterday. Now it barely works. I wonder if it is the proper way to move a file handle in this way.

The usage is still the same

myscript.pl targetfolder/*> result.csv

F is my file handle.

The argument I passed to the subroutine is the scalar $_, which is used by the if condition. When I want to move downward in my subroutine next if 1..4 will not work, so I repeat $a = <F>; a few times to achieve moving file handle downward.

But I think this is not a proper way to move the same file handle both in my main code and my subroutine. I am not sure it will really go through every line. I need your advice.

myscript.pl

#Report strip
use warnings;
use strict;

##Print the title 
Tfms2();

##Print the title 
print "\n";

@ff = <@ARGV>;

foreach $ff ( @ff ) {

    open (F, $ff);

    @fswf = @fschuck = @fsxpos = @fsypos = @fsdev = @csnom = ""; 
    @cswf = @cschuck = @csxpos = @csypos = @csnom = "";    # is there an efficient way?

    while (<F>) {
        Mfms2();
        Mfms3();
    }

    $r = 1;

    while ( $r <= $#fswf ) {      # because @fsws is the largest array
        Cfms3();   
        print "\n";
        $r++;
    }

    close (F);
}
##==========================================================================================
##Subs
##==========================================================================================

##FS II
sub Tfms2 {
    print "FS_Wafer,FS_ChuckID,FS_pos_X,FS_pos_Y,FS_deviation,CS_Wafer,CS_ChuckID,CS_pos_X,CS_pos_Y,CS_NofWafer_Ident_Spot";
}


sub Mfms2 {

    if ( /^F\sM\sSTATISTICS\sII$/ ) {

        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);

        $r = 1;

        @b = "";

        while ( $a !~ /\+\-/ ) {
            chomp $a;
            @b = split / *\| */, $a;

            $fswf[$r]    = $b[1];
            $fschuck[$r] = $b[2];
            $fsxpos[$r]  = $b[3];
            $fsypos[$r]  = $b[4];
            $fsdev[$r]   = $b[5];

            $r++;

            $a = (<F>);
            @b = "";
        }
    }
}


##FS III
sub Mfms3 {
    if ( /^F\sM\sSTATISTICS\sIII$/ ) {

        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);

        $r = 1;

        @b = "";

        while ( $a !~ /\+\-/ ) {
            chomp $a;
            @b = split / *\| */, $a;

            $cswf[$r]    = $b[1];
            $cschuck[$r] = $b[2];
            $csxpos[$r]  = $b[3];
            $csypos[$r]  = $b[4];
            $csnom[$r]   = $b[5];

            $r++;

            $a = (<F>);

            @b = "";
        }
    }
}


sub Cfms3 {
    print "$fswf[$r],$fschuck[$r],$fsxpos[$r],$fsypos[$r],$fsdev[$r],";
    print "$cswf[$r],$cschuck[$r],$csxpos[$r],$csypos[$r],$csnom[$r],";
}
Community
  • 1
  • 1
seedof
  • 11
  • 3
  • 1
    Last time, I asked you to fix your code indentation yourself in the future. If you can't be bothered to post readable code, why should we make the effort to help you? – Dave Cross Jul 15 '18 at 05:38
  • 3
    *The argument I passed to subroutine is a scalar* In this code, you do not pass anything into a subroutine anywhere. – Dave Cross Jul 15 '18 at 05:41
  • 4
    Please use the `strict` and `warnings` pragmas on code you post here. – Håkon Hægland Jul 15 '18 at 06:00
  • 2
    @seedof: I see you've edited your code to add `use strict` and `use warnings`. Because you haven't made any other fixes, the `use strict` now means your code doesn't even compile. Please be more careful. – Dave Cross Jul 15 '18 at 09:07
  • 1
    I also see that the same edit added an image of your input data. I will never understand why some people think it is useful to post an image of text. If I want to test code that I have written to help you solve your problem, then I need to retype your data. If you had just given us the text, I could have just pasted it into a test file. You seem to be doing all you can to prevent us from helping you :-/ – Dave Cross Jul 15 '18 at 09:57
  • 2
    Your program doesn't even compile! – ikegami Jul 15 '18 at 10:54

1 Answers1

4

You have forgotten to tell us what the program is supposed to do, so it's very hard to be any help. There might be more information in your previous question, but we don't all read every question here and you don't even include a link to your previous question.

The answer to your question is that you can use seek() to move to an arbitrary position in a file. You might also find it useful to look at tell() which can tell you where you currently are in a file.

But I don't think that information will be particularly helpful to you as you seem rather confused about what you're trying to do. If you were to explain your task in a bit more detail, then I strongly suspect that we could help you (and I also suspect that help would largely involve rewriting your code from scratch). But until you give us details, all we can do is to point out some of the more obvious problems with your code.

  • You should always include use strict and use warnings in your code.
  • I don't think that @ff = <@ARGV> does what you think it does. I think you want @ff = @ARGV instead. And, even then, that feels like you're copying @ARGV pointlessly.
  • Having an array (@ff) and a scalar ($ff) with the same name is going to confuse someone at some point. And, more generally, you need to put more effort into naming your variables clearly.
  • Please use the three-argument version of open() along with lexical filehandles. You should also always check the return code from open() - open my $fh, "<", $ff or die "Could not open $ff: $!".
  • Your lines like @fswf=@fschuck=@fsxpos=@fsypos=@fsdev=@csnom="" aren't doing what you think they are doing. You end up with a lot of arrays each of which contain a single element. Better to just declare the arrays with my - Perl will create them empty (my (@fswf, @fschuck, @fsxpos, ...)).
  • If you really need to skip eight lines when reading from your file then it's much clearer to write: $a = <F> for 1 .. 8.
  • You are making heavy use of global variables. There's a good reason why this goes against software engineering best practices. It makes your code far more fragile than it needs to be.

All in all, you seem to be guessing at a solution here, and that's never a good approach. As I said above, we'd like to help you, but without a lot more information that's going to be almost impossible.

Update: Looking at your code a bit more closely, I see that you are storing the data that you parse from the files in a number of arrays. Each array contains data from a single column of the input file and in order to get all of the data from a single row, you need to access each of these arrays using the same index value. This isn't a very good idea. Splitting linked data across different variables is a recipe for disaster. A far better idea would be to store each record in a hash (where the key would denote the data item that is stored) and to store references to all of these hashes in an array. This brings all of your data together in a single variable.

Updated update: I don't know enough about your data to be sure, but here's the kind of approach I would take. I've only parsed the data and then used Data::Dumper to display the parsed data structure. Producing better output is left as an exercise for the reader :-)

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

use Data::Dumper;

@ARGV or die "Usage: $0 file [file...]\n";

# Define two list of keys for the different types
my %cols = (
  II  => [qw(wf chuck xpos ypos dev)],
  III => [qw(wf chuck xpos ypos nom)],
);

my @data;     # To store the parsed data
my $cur_type; # Keep track of the current type of record

while (<>) {
  # Look for a record header and determine which type of 
  # record we're dealing with (I think 'II' or 'III').
  if (/^F M STATISTICS (III?)$/) {
    $cur_type = $1;
    next;
  }

  # Skip lines that are just headers/footers
  next if /\+[-=]/;
  # Skip lines that don't include data
  next unless /\d/;

  chomp;

  # Remove the start and end of the line
  s/^\|\s+//;
  s/\s+\|$//;

  # Store the data in a hash with the correct keys 
  # for this type of record
  my %rec;
  @rec{@{$cols{$cur_type}}} = split /\s+\|\s+/;

  # Store a reference to our hash in @data
  push @data, \%rec;
}

# Dump the contents of @data
say Dumper \@data;
Dave Cross
  • 68,119
  • 3
  • 51
  • 97