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

I am new to perl as of a couple weeks ago.

If it's easy, I would like to truncate an html file that I'm continuously adding one line of information to the top of. I would like to keep this file just 5 "lines" long. Lines are separated by an html line break in this case, not a new line character.

The html file is text only with no tags or formatting and completely empty at the start of the process.

New lines are added to the file such that $html_doc = "a new set - line 1 {br} $html_doc"

After 6 additions to the file, it looks like: (note: curly brackets are used below instead of < and > to illustrate)

a new set - line 6 {br}a new set - line 5 {br}a new set - line 4 {br}a new set - line 3 {br}a new set - line 2 {br}a new set - line 1

in a browser the file looks like:
a new set - line 6
a new set - line 5
a new set - line 4
a new set - line 3
a new set - line 2
a new set - line 1

I would like to use the simplest way to chop off anything past the 5th line break, IF there are that many lines. Otherwise, the entire file can stay as is.

Is there an easy way to do this?

Replies are listed 'Best First'.
Re: truncating a text file
by ikegami (Patriarch) on Jul 17, 2007 at 00:10 UTC

    Since you need to write the entire file to add to the front of it, just write 5 things back. Using truncate would actually be extra work.

    # Load old list. my @sets = do { open(my $fh, '<', $file) or die("Unable to open set list \"$file\": $!\n"); local $/ = '<br>'; <$fh> }; # Add new item to the top. unshift @sets, "a new set - line 7<br>"; # Keep the top 5. if (@sets > 5) { @sets = @sets[0..4]; } # Save new list. { open(my $fh, '>', $file) or die("Unable to create set list \"$file\": $!\n"); print $fh @sets; }

    Update: Fixed indexes on slice.

      I gave this one a try first. The couple snags I ran into were that you end up with 4 lines instead of five, as well as in reverse order. I wasn't very specific about sort order, sorry about that.

      The program outputs lines in the order of line 1,2,3,4,5 and just shoves things into the front so it will be displayed on top in the html page. Before removing the last line, the file would look like:

      line 1
      line 5
      line 4
      line 3
      line 2
      line 1

      and end in:

      line 1
      line 5
      line 4
      line 3
      line 2

      The goal is to make it so the file doesn't keep growing in this endless process, and to keep the most recent on top as it is a link to the most recent results.

      Being that I'm new to perl, this was the only suggestion I've been able to try so far. I'll continue reading to see if I can figure out the other suggestions and give them a shot.

      Thank you very much.
      ^_^

        Oops,

        # Keep the last 5. if (@sets > 5) { @sets = @sets[-5..-1]; }

        should be

        # Keep the first 5. if (@sets > 5) { @sets = @sets[0..4]; }

        It's a remenant of an incorrect version I wrote before posting.

        (I updated my earlier post to remove the error.)

Re: truncating a text file
by GrandFather (Saint) on Jul 17, 2007 at 00:12 UTC

    What does your current code look like? You may like to mock up a test script using a __DATA__ section to simulate the "input data" for the script.

    How you solve the problem depends a lot on whether you must parse the existing HTML document to determine what past lines were, or if you have them available in some other fashion and can simply recreate the HTML file with the new data.

    HTML::TreeBuilder will help a lot if you have to parse the data and HTML::Template will help generate the new file. At some point an array slice (see perldata - slices) will help extract the last five lines.


    DWIM is Perl's answer to Gödel
Re: truncating a text file
by Cody Pendant (Prior) on Jul 17, 2007 at 04:50 UTC
    Maybe I'm missing something, but isn't it as simple as this?
    $str = 'line 5<br>line 4<br>line 3<br>line 2<br>line 1<br>'; @lines = split('<br>',$str); unshift (@lines,'line 6'); $output = join('<br>',@lines[0..4]); print $output;


    Nobody says perl looks like line-noise any more
    kids today don't know what line-noise IS ...

      That gives warnings and extra <br>s when there aren't five lines yet.

      >perl -we"@lines = qw( a b c ); print join '<br>', @lines[0..4]; Use of uninitialized value in join or string at -e line 1. Use of uninitialized value in join or string at -e line 1. a<br>b<br>c<br><br>

      Also, given $html_doc = "a new set - line 1 {br} $html_doc", you're short a br when there are five lines.

        i think the code should be as follows, to prevent the warnings
        $str = 'line 5<br>line 4<br>line 3<br>line 2<br>line 1<br>'; @lines = split('<br>',$str); unshift (@lines,'line 6'); $output = join('<br>',@lines); print $output;
        the hardest line to type correctly is: stty erase ^H
Re: truncating a text file
by aquarium (Curate) on Jul 17, 2007 at 03:58 UTC
    i'd actually use a different tack and that is, use Tie::File module, letting the module take care of the correct file reading/writing...you just maintain a 5 element array or hash, depending on which (hash or array) is most suitable.
    the hardest line to type correctly is: stty erase ^H