Perl newbie
Perl newbie

Reputation: 25

PERL:To write in input file (without overwrite the original file)

Below is my input file as well as acts my output file too. Need assistance to read and write in the input file. (PS: Input and output is same file)

 TS_dunit_       PDX_VER_6
 TS_test1_par    PDX_VER_0

my code look likes below;

#!/usr/perl/5.14.1

use Getopt::Long;
use strict;
use warnings;

my $file;

GetOptions(
   "iofile=s" => \$file
   );
if (not defined $file){
print "Please specify input_output (iofile) file\n";
exit;
}

open (my $fh, "$file") or die "Can't open the file $file: ";
open (my $fh1, ">>$file") or die "Can't open the file $file: ";

while (<$fh>){
chomp $_;
next if ($_ !~ /S+/);
$_ =~ /(\S+)\s+(\S+)/;
my $first_underscore =index ($1, '_');
my $dev = substr ($1, $first_underscore + 1,
        rindex ($1, '_') - $first_underscore - 1);
my $tag  = $2;
my $cat_path = "/testdata/17.26.6/$dev/sd/$tag";
my $arc_path = "archive/$dev/sd/$tag";
if (-d $cat_path){
            print $fh1 "$dev $tag IN_CAD\n";
    }elsif (-d $arc_path){
            print $fh1 "$dev $tag IN_ARCHIVE\n";
    }else{
            print $fh1 "NA\n";
    }

}
   print "Done! File been append.\n";   

Above code gives output as

  TS_dunit_          PDX_VER_6       
  TS_test1_par       PDX_VER_0        


  IN_CAD 
  IN_CAD 

need help if anyway i can make the output as below instead.

  TS_dunit_          PDX_VER_6     IN_CAD   
  TS_test1_par       PDX_VER_0     IN_CAD   

Upvotes: 2

Views: 1147

Answers (1)

zdim
zdim

Reputation: 66883

One cannot append to a line in a file without overwriting the rest of the file. A file is a sequence of bytes and we can't "insert" new ones, only overwrite the existing ones (or add more by extending the file). See this post for more detail, for instance.

Instead, write out a new file and then rename it to the original. This does change the inode number; if you need to keep it see the end. The code simplifies the index+substr part, by regex.

use warnings;
use strict;
use feature 'say';
use File::Copy qw(mv);

# ... code from the question 

open my $fh,     '<', $file    or die "Can't open $file:$!";
open my $fh_out, '>', $outfile or die "Can't open $outfile:$!";

while (<$fh>) 
{
    next if not /\S/;
    chomp;

    my ($dev, $tag) = /.*?_(.*)_\s+(.*)/;

    my $cat_path = "/testdata/17.26.6/$dev/sd/$tag";
    my $arc_path = "archive/$dev/sd/$tag";

    if (-d $cat_path) {
        say $fh_out "$_ IN_CAD";
    } 
    elsif (-d $arc_path) {
        say $fh_out "$_ IN_ARCHIVE";
    }
    else {
        say $fh_out "NA";
    }
}
close $fh;
close $fh_out;

# Changes inode number. See text for comment
move($fh_out, $fh) or die "Can't move $fh_out to $fh: $!";

The regex matches up to the first _, since ? makes .*? non-greedy (it stops at first _). Then it captures everything until the last _ since .* is greedy, matching everything until the very last _. This is what the code in the question does, by using rindex. Then it captures all after tabs/spaces.

The current line is then printed appended, as in the question, to the output file. Since the output file is temporary its name should be built using File::Temp. Then the file is renamed using File::Copy.

This changes the inode number. If that matters, one way to keep the inode number is as follows. After the output file has been written out open the original file for writing, what will clobber it. Then read from the output file and write to the original file. The content gets copied, to the same inode. Remove the output file when done. See more detail in the post linked in the beginning.

Upvotes: 1

Related Questions