in reply to replacing in file

In the first code example, all you're doing is modifying the contents of $_ in the while loop, and then not bothering to do anything with it. In the second example...

open (OUTFILE, "<$dirContent");

You just opened your "out file" for reading. You wanted...

open (OUTFILE, ">$dirContent");

Worse still... You're opening the same file twice! You have two choices for what you want to do... Either open the original file for reading, and a new one for writing, then rename the new to the old when you're done, or better still, do this all from the command line (which will basically do the same thing under the hood.

perl -p -i.bak -e '/oldstring/newstring/'

Having to write a whole new file may seem unfortunate and inefficient, but you don't really have much choice. A file is a contiguous block of bytes, and if you grow or shrink a piece of it, you basically have to shift all the following pieces around, or rewrite the whole file. The only way around rewriting the whole file is to have a file of fixed record lenghts, or to store modification information at the end of the file, and have a very dynamic, on the fly type of data extraction occuring. The latter is how a lot of text editors work, recording lots of small changes at the end of the file, and every now and again performing a monolithic clean up and synchronization.

Replies are listed 'Best First'.
Re: Re: replacing in file
by jc23 (Acolyte) on Aug 01, 2003 at 17:57 UTC
    Hey skyknight
    The problem with the one liner is that it's actually part of a bigger script. I tried calling the one liner perl program in a larger program, but it doesnt do the job. For some oddball reason, I wanted to replace the line "To: <list of email addys>" to just "To: me@home.com". The regex I used only got rid of the To: and left everything else. Here's the one liner in my perl script:
    `perl -p -e 's/^To: [\.\@\D\,]*/To:me@home.com/' Mailbox`;
    Can you give me any other specifics?
      Here's (roughly) what Perl does when you use the -pi.bak flag on the file filename (and what you'll have to emulate):
      1. Open the file "filename" for read, with handle READ
      2. Rename "filename" to "filename.bak"
      3. Open the file "filename" for write+truncate with handle WRITE
      4. Read through all the lines from READ, modify them, then print them to WRITE

      It's not working because you lost the -i switch, which specifies edit-in-place. Do "perl --help" to get a list of command line switches. You really shouldn't invoke an external process, though, if you don't have to do so. Just follow the other idiom I mentioned. To elaborate...

      open(OLD, "<old.txt") or die "can't open original file: $!"; open(NEW, ">new.txt") or die "can't open new file: $!"; while(<OLD>) { s/whatever/somethingelse/; print NEW; } close(OLD); close(NEW) rename("new.txt", "old.txt");