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

I just want to say thank you to everyone for all of the information. I changed the script as Ikegami suggested and not only works good but it made it more clear how Perl loops through the data . It seems to me that the foreach statement only process one line at a time as with each item withen the loop and continues so until all lines in the orignal data file were processed. I was confused because I thought it processed all the lines for each item whiten the loop and only made one pass I hope my though process is clear on this now so I can move on

Hello Everyone , I am new to Perl . I am creating a program and the below code works the way I want it to .
I actually got this code snippet from the internet and use it for my program.
My problem is I do not quite understand how it works? I have done some experimentation on it.
Well the first part is easy . @main is a place holder for the data in date.txt the foreach seems to take the data from @main and put in $line_in
The if statement seems to search and remove any instance of "The marker line" Then proceeds to print "hello" into date.txt. then it loops again ???? and does not
find "The marker line" so it returns an exit code of 0 ???? and moves to the else statement. ???? The else statement then copies the contents of $line_in to date.txt ,
the contents after the if statement removes "The marker line" ????
I am really confused and dont know if I am on the right track can anyone help?

open(FILE,"date.txt") || die $!; @main = <FILE>; close(FILE); open(FILE,">date.txt") || die $!; foreach $line_in (@main) { if ($line_in =~ /The marker line/) { print FILE "The marker line\n"; print FILE "hello\n"; } else { print FILE "$line_in"; }

Replies are listed 'Best First'.
Re: regular expression
by ikegami (Patriarch) on Oct 31, 2010 at 17:02 UTC

    The idea is to insert 'hello' after the marker line. For each line, it either prints the line plus hello (if it's the marker line) or just the line. The loop body could be written better as

    print FILE $line_in; if ($line_in =~ /The marker line/) { print FILE "hello\n"; }
      For each line, it either prints the line plus hello (if it's the marker line) ...
      That is not entirely true.

      The test checks if the line contains the literal text "The marker line", but there could be other text before or after it. However, it wil then only print "The marker line" into the file, actually discarding some "garbage" text.

      CountZero

      A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

        I said "The idea is". I realise it doesn't quite succeed at executing it.
Re: regular expression
by AnomalousMonk (Archbishop) on Oct 31, 2010 at 21:14 UTC
    shevek: It re-opens the same file for output.

    toniax: You say you are new to Perl programming, and by implication you may be new to programming in general. If so, it is well to point out a critical side-effect of your OPed program: When the file is re-opened for output, the original content of the file is destroyed. The only place the original file content still exists is in an array in your program. If your program should fail for any reason before the original content is completely processed, the output file will be left only partly full of processed data – and possibly entirely empty.

    One approach to handling a situation like this (in which processed output data is intended to be held in a file with the same name as the input file) would be:

    1. Open a temporary file (e.g., date.txt.out) and write processed data to this file. When processing is complete and the temp file is closed without error,
    2. the original input file is renamed (e.g., to date.txt.bak). If the input file rename operation is error-free,
    3. the output file is renamed to its final form (e.g., date.txt), and if this operation is successful,
    4. perhaps delete the temporarily renamed input file (although this file may instead be left behind as a .bak file).

    Note that error checking is vital at each stage of this process. In this way, much grief may be avoided.

      Yes I am new to programing in the sense that , I want to learn how it works. I can take snippets of code and put it together and make a program . I will work but be a program that is full of flaws such as you point out to me . You made some great points and I will use your advice and change my program for the better of data preservation. So much more for me to learn. I really do appreciate all the help everyone is giving me . Thanks again
      Hello I changed my program . And added the features you suggested. I know a better way must exist . Can any one help.
      $openx = open(BAKFIL, "<data.txt"); open(BAKFIL2, ">data.bak.txt"); if ( ! $openx ) { print "Content-type:text/html\n\n"; print "File Does not exist. Program will now abort"; close( BAKFIL ); close( BAKFIL2 ); unlink( "data.bak.txt"); exit ; } else { while(<BAKFIL>) { print BAKFIL2 $_; } close( BAKFIL ); close( BAKFIL2 ); } my $filesize = -s "data.txt"; open(XFIL,"data.txt") || die $!; @main = <XFIL>; close(XFIL); open(XFIL,">data.txt") || die $!; foreach $main_line (@main) { print XFIL $main_line; if ($main_line =~ /The marker line/) { print XFIL "Hello\n"; } } close(XFIL); my $filesizemain = -s "data.txt"; if ($filesizemain < $filesize) { open(BAKFIL2, "<data.bak.txt") || die $!; open(BAKFIL, ">data1313.txt") || die $!; while(<BAKFIL2>) { print BAKFIL $_; } close( BAKFIL2 ); close( BAKFIL );
Re: regular expression
by shevek (Beadle) on Oct 31, 2010 at 17:17 UTC
    Hello,

    @main is an array that contains a line of the input file for each index. The program is opening the file and reading the contents into the main array in one statement. It then closes the file. It re-opens the same file for output. It loops through the array main trying to match on the string "The marker line". When it finds a match, it prints out "hello" after the match string.

    Please read the perl faq on arrays and file handling. If you plan on developing, or maintaining, perl code going forward then please understand @, $, % and the difference between scalar and list context. You can go a long way with that understanding (especially if you can throw references in the mix as well).

Re: regular expression
by toniax (Scribe) on Oct 31, 2010 at 20:33 UTC
    I just want to say thank you to everyone for all of the information.
    I changed the script as Ikegami suggested and not only works good but it made it more clear how Perl loops through the data .
    It seems to me that the foreach statement only process one line at a time as with each item withen the loop and continues so until all lines in the orignal data file were processed.
    I was confused because I thought it processed all the lines for each item whiten the loop and only made one pass I hope my though process is clear on this now so I can move on