Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi all,
Can anyone help me to modify this perl code.
#!/usr/bin/perl open(DATA,"<a.txt") or die "Caanot read $!"; @info=<DATA>; close(DATA); open(FH,"+>b.txt") or die "Not able to create"; foreach (@info) { $_ =~ s/NULL//g; $_ =~ s/ //g; } print FH "@info"; close(FH); system("mv b.txt a.txt"); a.txt data ===== This is a test line Contains NULL values NULL Testing Testing in Progress

Is there anyway to modify the file instead of creating new one and replace by old one?
Thanks

Replies are listed 'Best First'.
Re: Best way to write in Perl
by atemon (Chaplain) on Sep 04, 2007 at 06:31 UTC

    Hi,

    Tie::File may be of your choice. It fetches file line-by-line to an array. Whatever you do with the array will reflect in the file like editing, adding or deleting a line. They say :

    Tie::File represents a regular text file as a Perl array. Each element in the array corresponds to a record in the file. The first line of the file is element 0 of the array; the second line is element 1, and so on. The file is not loaded into memory, so this will work even for gigantic files. Changes to the array are reflected in the file immediately.

    You can push, pop, shift and unshift the array to append, delete from end, delete from beginning and add at beginning. Splice on array can remove a line from array :)

    Cheers !

    --VC



    There are three sides to any argument.....
    your side, my side and the right side.

      Thanks a lot for your help
Re: Best way to write in Perl
by Corion (Patriarch) on Sep 04, 2007 at 06:30 UTC

    It's not clear to me whether you want to append to the file b.txt or whether you want to overwrite it. See open for the various parameters you can pass to the open function to tell it what it should do to the file b.txt.

      Hi,
      I want to over write data in a.txt.
      I am expecting output in a.txt as
      Thisisatestline Containsvalues TestingTestinginProgress Currently I am reading a.txt, store those data in an array. Then creating b.txt and replacing NULL and spaces from a.txt. Finally replacing a.txt by b.txt using mv command. Can you please provide best method to handle this?
      Thanks

        This doesn't sound too bad to me. Especially, your solution is safe from errors if your program crashes before the new output has been written completely. Why are you trying to change that?

Re: Best way to write in Perl
by cdarke (Prior) on Sep 04, 2007 at 10:59 UTC
    A pet peeve of mine: please don't do this:
    system("mv b.txt a.txt");
    because it creates an unwanted child. Use rename instead:
    rename('b.txt', 'a.txt');
Re: Best way to write in Perl
by Skeeve (Parson) on Sep 04, 2007 at 06:42 UTC
    You could use the switch "-i.bak". Please read Perl's man page.

    s$$([},&%#}/&/]+}%&{})*;#$&&s&&$^X.($'^"%]=\&(|?*{%
    +.+=%;.#_}\&"^"-+%*).}%:##%}={~=~:.")&e&&s""`$''`"e
      Thanks
Re: Best way to write in Perl
by perl_fan (Novice) on Sep 04, 2007 at 08:00 UTC
    hello fellow monk,
    
    yes there is a facility in perl to modify a file (i.e. to do inline replacement)
    
     perl -pi -e 's/MONK/SAINT/ig' abc.txt
    
    The above file will replace all the instances of MONK to SAINT in the file abc.txt
    
    hope it helps,
    
    Blessings,
    a perl Monk
    
      I think you forgot to create a backup of the file. I tried:

      perl -pi -e 's/MONK/SAINT/ig abc.txt

      and get:

      Can't do inplace edit without backup.

      If you change that to:

      perl -pib -e 's/MONK/SAINT/ig' abc.txt

      Then it works ;)


      Smoothie, smoothie, hundre prosent naturlig!
        Actually, just specifying -i will work on most platforms. Cf perldiag :
        Can’t do inplace edit without backup (F) You’re on a system such as MS-DOS that gets confused if + you try reading from a deleted (but still opened) file. You have t +o say "-i.bak", or some such.
Re: Best way to write in Perl
by scorpio17 (Canon) on Sep 04, 2007 at 14:20 UTC

    Here's another way: Open the file in "update mode", which lets you read and write at the same time. Read everything in and modify as before, then rewind the file pointer back to the beginning, write out the modified content, then close the file. The trick here is that if the new version is shorter than the original, you need to trim off the extra stuff on the end - that's what 'truncate' does. This will let you modify the file in place, with no backup. But it does assume that everything can be slurped into memory at one time, so it won't scale well for large input files.

    use strict; # open in read/write mode open(DATA, "+< a.txt") or die "Cannot read $!"; my @info = <DATA>; foreach (@info) { $_ =~ s/NULL//g; $_ =~ s/ //g; } seek(DATA, 0, 0); # rewind back to beginning foreach(@info) { print DATA; } truncate(DATA, tell(DATA)); close(DATA);