Search code examples
perlfilehandle

perl process inlude files recursively


I would like to process files recursively.

I have a config file, and this config file can include an "include" statement. Once the include-statment is identified, the file shall be processed. It could happen, that in the file processed again an include-statement can show up.

So something like this:

  • config file
  • process lines of first level
  • include file (process now)
    • process line of second level
    • -include file (process now) - process and close
    • process further lines of second level
    • close file
  • process more lines of first level
  • close file

For this to manage I have created a subroutine: Update ---- call for sub updated!

my $av_fn_FH;
my $av_tmp_LINE;
my @av_arr_FN;
sub processfile
{
  open($av_fn_FH, "<", "$_[0]")
  while($av_tmp_LINE = readline($av_fn_FH)) 
  { 
    if ( substr($av_tmp_LINE,0,7) eq "include" )
    {
      @av_arr_FN = split(" ", $av_tmp_LINE); # get the filename from the include statement
      processfile($av_arr_FN[1]); # process the include file
    }
    # do something with "normal" lines
  }
  close($av_fn_FH);
}

This recursive calling of the subroutine does not work. Once comming back from the subroutine the HANDLE is reported as closed.

The docu for the open statement says: "Associates an internal FILEHANDLE with the external file specified by EXPR." I expected the FILEHANDLE as unique!

I would apreciate some hints how to get this done!


Solution

  • Your filehandle is declared outside of the subroutine; so you over-write the value when you open a new config file, and then close it.

    sub processfile
    {
        open(my $fh, "<", $_[0])
            or die "Can't open $_[0]: $!";
    
        while(my $line = readline($fh)) { 
            if ($line =~ /^include\s+(\S+)/) {
                # $1 is the filename after "include "
                processfile($1);   # process the include filename
                next; # skip "normal" stuff below
            }
            # do something with "normal" lines
        }
        close($fh); # optional; closes anywhen when $fh goes out of scope
    }
    

    In general, you want to declare your variables in as small a scope as possible where they're actually used.