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

How do I modify a file without using a temporary file, without using a module, and without putting the whole file into an array or something? I have the following code, but I'm unsure why modifying $_ doesn't change the file:
sysopen(TOPIC, "$root/content/topics/$get{'topic'}", O_WRONLY); $/ = ""; while(<TOPIC>) { if( /^$get{'post'}/ ) { s/.*\n$/$post/m; } } close(TOPIC);

Replies are listed 'Best First'.
Re: modifying a line in a file with some restrictions
by BrowserUk (Patriarch) on Jan 14, 2003 at 07:45 UTC

    I'm unsure why modifying $_ doesn't change the file

    • Your opening the file write-only (O_WRONLY),
    • attempting to slurp the entire file ($/=""),
    • Testing to see if it contains some text return by $get{'post'} (whatever that is!)
    • Replacing everything in the file (if the file ends with a newline) with whatever is in the variable $post.
    • Then closing the file without having re-written the (possibly) modifed data back out

    Still unsure why? :^).


    Examine what is said, not who speaks.

    The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

      attempting to slurp the entire file ($/="")
      No, he's reading it in paragraph mode. See perlvar. Update: That is, of course, he would be reading it in paragraph mode if he had opened it for reading.
      Replacing everything in the file (if the file ends with a newline)
      No, he is only replacing the first line of the paragraph.

      Makeshifts last the longest.

        Good point about the paragraph mode, but he's not reading anything from a file opened write-only.

        However, if he was reading a paragraph, it wouldn't be the first line of the paragraph he would be replacing.

        The text replace would be the last line of the paragraph plus the two or more newlines that delimited the paragraph. Somehow I doubt that this was his intention, but the point is mute until he manages to read something in.

        Seems we both need to read perlop, and possibly perlre as well ....


        Examine what is said, not who speaks.

        The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

Re: modifying a line in a file with some restrictions
by Aristotle (Chancellor) on Jan 14, 2003 at 09:03 UTC
    sysopen(TOPIC, "$root/content/topics/$get{'topic'}", O_WRONLY);
    That is almost certainly a broken CGI script I see there. Please do yourself the favour and read Ovid's excellent CGI course, there are many security and safety issues to consider.

    Makeshifts last the longest.

Re: modifying a line in a file with some restrictions
by graff (Chancellor) on Jan 14, 2003 at 07:38 UTC
    ...without using a module, and without putting the whole file into an array or something? ... Um, well... you are already reading the whole file into a scalar, and modifying that scalar, so you're close; this get you rest of the way (mostly -- but it's not tested):
    $/ = undef; $filename = "$root/content/topics/$get{'topic'}"; open( TOPIC, "+<", $filename ) or die "Unable to read/write $filename\ +n"; $_ = <TOPIC>; if( /^\Q$get{'post'}\E/ ) { s/.*\n$/$post/m; } seek( TOPIC, 0, 0 ); # rewind to start of file print TOPIC; close TOPIC;
    Since this seems to be part of a CGI process, we have to raise the standard "issues"... You need to apply some form of file locking, because two browsers could try to make distinct changes on the same file at the same time. You probably need to include taint checking (at least), or employ some reasonably secure way of specifying the name of the file to be opened and over-written. (I've added the "easy" part: the contents of $get{post} need to be enclosed within the "quote-meta" operators \Q...\E, in case it happens to include things like period, plus, asterisk, parens, brackets, and so on, which might cause a run-time error or mis-match.)
Re: modifying a line in a file with some restrictions
by yodabjorn (Monk) on Jan 14, 2003 at 06:53 UTC
    you can find your answers in modifying and overwriting a file
    Basically you want:
        $^I = '.bak';
    (inplace editing)

    An intellectual is someone whose mind watches itself.
    - Albert Camus