0

Update: I modified my code but it still can't update all the files properly (no compilation issues and I can open/read all the files as well). Can someone please take a look what I am doing wrong. My updated code is below:

I have a follow-on question that I asked earlier. I have a directory named Perl which has three .txt files, namely fil1.txt, file2.txt and file 3.txt.

Content of file 1

line1
line2
TAG1 "some_name:tag1"
line4
TAG2 "some_name:tag2"
line5
TAG3 "some_name:tag3"

Content of file2.txt

line1
line2
TAG1 "some_name_file2:tag1"
line4
TAG2 "some_name_file2:tag2"
line5
TAG3 "some_name_file2:tag3"

Content of file3.txt

line1
line2
TAG1 "some_name_file3:tag1"
line4
TAG2 "some_name_file3:tag2"
line5
TAG3 "some_name_file3:tag3"

I want to replace all the lines that begin with the TAG with "hello_wolrd" such that the line should be something like this:

TAG1 "hello_world"
TAG2 "hello_world_2nd_time"
TAG3 "hello_world_3rd_time".

How do I achieve this? I get the error message that reads "Can't open the file" Here is my code:

  #! /usr/bin/perl

use strict;
use warnings;
use Data::Dumper;


my $dir = "path to my dir";
my @tmp = ();

opendir( my $DIR, "$dir") or die "Can't open directory, $!";
my @list = readdir($DIR);
my @list2 = sort grep(/^.*\.txt$/, @list);

foreach(@list2)
{
    push(@tmp, "$_\n");
}
closedir ($DIR);

print ("Tmp = @tmp\n");
foreach my $cur_file (<@tmp>) {

    my $fh;

    print "Current file = $cur_file\n";
    open($fh, '<', "$cur_file") or die "Can't open the file\n";
    while(<$fh>){
        chomp($_);
        my $line = $_;
        print "Current line is $line\n";
        if($line =~ /Tag1/)
        {
            $line =~s/\"\S+\"/"hello_world_1st_time"/g;
            push(@tmp, "$line\n");
        }
        elsif($line =~ /Tag2/)
        {
            $line =~s/\"\S+\"/"hello_world_2nd_time"/g;
            push(@tmp, "$line\n");
        }
        elsif($line =~ /Tag3/)
        {
            $line =~s/\"\S+\"/"hello_world_3rd_time"/g;
            push(@tmp, "$line\n");
        }
        else 
        {
            push(@tmp, "$line\n");
        }
    }       

    close($fh);

#   print Dumper @tmp;
    open ($fh, '>', "$cur_file") or die "Can't open file\n";
    print $fh @tmp;
    close($fh);
    undef @tmp;

}
3
  • You are doing yourself no favours by abstracting your example so far from your real code. What is Path to perl directory, for instance? It makes a big difference. Commented Apr 14, 2014 at 21:45
  • It seems to me that $cur_file will now contain a trailing newline. Try printing it as first thing in the for loop with some end-marks like this: print ">$cur_file<\n"; Commented Apr 16, 2014 at 4:41
  • Another thing, you'd be probably better off reading the lines into $line directly. while (my $line = <$fh>) Commented Apr 16, 2014 at 4:53

3 Answers 3

1

You're using single quotes around your filename:

open($fh, '<', '$cur_file') or die "Can't open the file\n";

To fix, just remove the single quotes:

open($fh, '<', $cur_file) or die "Can't open the file\n";

Additionally, you should get more helpful error messages by examining $!. If you had, you would've been told exactly why it couldn't open the file.

However, for an easier solution, just put use autodie; at the top of your script below your use strict; and use warnings; statements. If you had that, you would've gotten the following error message:

Can't open '$cur_file' for reading: 'No such file or directory'
Sign up to request clarification or add additional context in comments.

3 Comments

That is one of the errors, but there are some more. For example, the glob doesn't read contents from a directory. It should pass a basic regular expression or use readdir(). And it neither uses a regular expression comparison ignoring case, to say a few. Besides that, use an array hardcoding the text instead of replacing it, is very weird for me.
@Birei: You should post your additional notes an an answer of your own
@Birei The fact that the OP reached the line to fail to open implies he has something in the glob that works. He also is printing out the contents of $cur_file before trying to open, so I think it's fair to assume he's already verified that works correctly.
1

I prefer to solve this kind of tasks using the -p (or -n) with -i switches. It creates a backup an iterates over all input files automatically. You save a lot of typing:

perl -i.bak -pe '
    BEGIN { %pos = qw{1 1st 2 2nd 3 3rd} } 
    s/^(TAG)(\d+)(\s+)(.*)$/$1 . $2 . $3 . "hello_world_" . $pos{$2} . "_time"/e
' ./your/dir/*.txt

The BEGIN block only is executed once and I create a hash to replace each number with its position, and the substitution instruction runs for each line of all input files, and when it finds a line that begins with TAG followed by a number, it checks the hash and replaces the whole line. In my testt it yields:

==> your/dir/file1.txt <==
line1
line2
TAG1 hello_world_1st_time
line4
TAG2 hello_world_2nd_time
line5
TAG3 hello_world_3rd_time

==> your/dir/file2.txt <==
line1
line2
TAG1 hello_world_1st_time
line4
TAG2 hello_world_2nd_time
line5
TAG3 hello_world_3rd_time

==> your/dir/file3.txt <==
line1
line2
TAG1 hello_world_1st_time
line4
TAG2 hello_world_2nd_time
line5
TAG3 hello_world_3rd_time

Comments

1
#! /usr/bin/perl

use strict;
use warnings;


my $dir = "path to my dir";

opendir( my $DIR, "$dir") or die "Can't open directory, $!";
while (my $file = readdir $DIR) {
    next if $file !~ /\.txt$/;
    say $file;
    open($in, '<', $cur_file) or die "Can't open the file '$cur_file'\n";
    my @lines = <$in>;
    close $in;
    foreach my $line (@lines) {
        if($line =~ /Tag1/)
        {
            $line =~ s/"\S+"/"hello_world_1st_time"/g;
        }
        elsif($line =~ /Tag2/)
        {
            $line =~ s/"\S+"/"hello_world_2nd_time"/g;
        }
        elsif($line =~ /Tag3/)
        {
            $line =~ s/"\S+"/"hello_world_3rd_time"/g;
        }
    }       

    open ($out, '>', $cur_file) or die "Can't open file '$cur_file'\n";
    print $out @lines;
    close($out);
}


closedir $DIR;

Alternatively, use Path::Tiny as you can see in this article: http://perlmaven.com/how-to-replace-a-string-in-a-file-with-perl and if you need to do this in a whole directory tree, this article might help: http://perlmaven.com/finding-files-in-a-directory-using-perl

(disclaimer: I run the Perl Maven site)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.