0

I am very new to Perl and I need to write a Perl script to do the following:

  1. Traverse a directory recursively and only process files with a specific extension (e.g .txt).
  2. For each .txt files, I need to either prepend a header to the file or update the header if the header already exists.

The header looks something like this:

//-----------------------------------------//
  Model : Info1
  Date  : Info2 
  Name  : Info3
//-----------------------------------------//

What I have done so far:

use File::Find;
use Cwd qw(getcwd);
use strict;

sub gen_header {
   my $divider = "//------------------------------------//\n";
   my $time = localtime();
   my $modelpath = getcwd();
   my $user = (getpwuid($<))[0];
   
   my $header;
   $header .= $divider;
   $header .= "//Model         : $modelpath\n";
   $header .= "//Date          : $time\n";
   $header .= "//Name          : $user\n";
   $header .= $divider;
   $header .= "\n";
   return header;
}

my $dir = "/src/dir1";
find (\&process_file, $dir);

sub process_file {
   my $filename = $_;
   my $out_file = $_.out;
   if (-f and /\.(txt)$/) {

      open (my $fh1, "<", $filename) || die "ERROR";
      open (my $fh2, ">", $out_file) || die "ERROR";
      
      if  (*header already exist*) {
         #Update header
         *code to update Info1, Info2 and Info3 in the header;*
      } else {
         #Prepend the header
         print $fh2 gen_header();
         while (<$fh1>) {
            print $fh2 $_;
         }
      }
      close $fh2;
      rename ($out_file, $filename) or die "Rename error";
   }
}

I have managed to create a subroutine to generate the header required and I'd like to believe that the way I am traversing the directory recursively and processing the files is correct. Though, I am having trouble figuring out how to update the header after that. So question,

  1. How do I do the "update header" part of the code? The gen_header subroutine returns a new header with the latest info every time its run but how do I use it to replace the old header?
  2. Is the way I am traversing a directory recursively and processing files correct or is there a better way to do what I want?
Xflkekw
  • 35
  • 2
  • 7
  • I have added the details to the gen_header subroutine. As for the update header, that is the part where I have no idea how to do. – Xflkekw Nov 24 '20 at 15:23

1 Answers1

1

I can't be more specific, without seeing how you're getting your 'header' details.

However based on what you've supplied so far:

How do I do the "update header" part of the code? The gen_header subroutine returns a new header with the latest info every time its run but how do I use it to replace the old header?

You've said you're updating a header, so I'm going to assume it already exists.

But:

open ( my $input, '<', "existing_file" ) or die $!;
open ( my $output, '>', "new_file" ) or die $!;
select $output; 
print $my_new_header; # will go to $output

my $seen; 
while ( <$input> ) {
   m,//-----, && $seen++;  
   #this will skip until the second instance of '//-----' in your file, 
   # so it'll 'eat' the whole file if there's no header at all. 
   next unless $seen >= 2; 
   print; 
}

Alternatively, if you can reliably detect the presence of a header, you could do this same approach with search-and-replace:

while ( <$input> ) {
   s/Model\s+: .*/Model : $my_model/;
  # etc.
  print;
}

Note: If your start and end markers were slightly different, you could use if ( m,//---, .. m,//--, ) { type syntax, but this won't work if the two matches are identical.

Is the way I am traversing a directory recursively and processing files correct or is there a better way to do what I want?

File::Find is the tool for that job, and what you're doing is fine.

You're capturing (txt) needlessly though, but that's a fairly minor thing.

if (-f and /\.(txt)$/) {

Unless you need $1 to contain 'txt' for some reason, you'd be better off with /\.txt$/ for clarity reasons.

Sobrique
  • 52,974
  • 7
  • 60
  • 101
  • I have added the details to the gen_header subroutine. For a given .txt file, I would like to check whether the header exists. If it does, then proceeds to update it with a new header with the gen_header subroutine. If no header is detected, then I would like to prepend a header to the .txt file with the same gen_header subroutine. – Xflkekw Nov 24 '20 at 15:40
  • I am pretty new to Perl. Can you explain the m,//-----, && $seen++; syntax? – Xflkekw Nov 24 '20 at 16:32
  • `m//` is regex match. `$seen++` means increment a counter, which you then test subsequently. So it'll ping when you've hit the regex twice, matching the start/end delimiters of your header. – Sobrique Nov 26 '20 at 11:14