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

Hello Monks , I am writting a script that would append or add information to a file that contain names. my file looks like this :
Mary Sue Kim
I want to add one more name to that file and make sure the name doesn't exists already. I am trying somthing like :
print " Enter the number of student that you want to add\n"; my $std = <STDIN>; chomp $std; open(FILE, "$stdInfo") || die "couldn't open $stdInfo for reading"; my @in=<FILE>; close(FILE); open (FILE, ">$stdInfo") ||die "couldn't open $stdInfo for writing"; for (@in) { print FILE unless ( $_ =~ /^\Q$std\E\b/ ); print $std; } close(FILE);
not working for me . Can someone help?

Replies are listed 'Best First'.
Re: appending to a file
by davido (Cardinal) on Feb 26, 2004 at 05:18 UTC
    The ">" argument to open means "truncate existing file and open for output" or "open a new file for output", depending on if the file exists already or not. Note, that's a lot different from appending.

    Append is ">>" (two >'s next to each other).

    In other words, instead of this:

    open FH, ">filename" or die "Bleah!\n$!";

    File level appending is opened like this:

    open FH, ">>filename" or die "Bleah!\n$!";

    Have a look at perlopentut for details.

    However, your code looks like it's trying to slurp in the file first, and then write it back out from scratch, while adding the new stuff at the end. Ok, that's one strategy, but it's not exactly the same thing as doing a file append.

    As for your code, a better solution (since you also seem to be doing some processing on the current file, if it exists) would be this:

    Open the input file. Open a temporary output file. Read the input file line by line. Process one line of input. Write it out to the output file. When done, append your additional information to the output file. Close the input file. Close the output file. Then rename your temp file so that it replaces your input file. Do your writing in standard ">" mode, because you're writing a new temp file, not appending to an existing file.


    Dave

      Open the input file. Open a temporary output file. Read the input file line by line. Process one line of input. Write it out to the output file. When done, append your additional information to the output file. Close the input file. Close the output file. Then rename your temp file so that it replaces your input file. Do your writing in standard ">" mode, because you're writing a new temp file, not appending to an existing file.

      This is quite the long-winded approach. Why would you want to have to read and then write back out each line, even ones that are not being modified? Too much file input/output! Take a look at my solution. It simply scans the file once over and appends the data (if necessary) at the very end. Simple yet efficient.

        This is quite the long-winded approach.

        Long winded, eh?

        perl -ni -e "BEGIN{ print qq/Enter new student's name:\n/; $name = <ST +DIN> } next if /^\Q$name\E\b/; print $_ . ( eof ) ? $name : q// " myt +est.doc

        Maybe you're right. ;)


        Dave

Re: appending to a file
by eyepopslikeamosquito (Archbishop) on Feb 26, 2004 at 05:59 UTC

    Consider what will happen if this line fails (due to temporary disk full, for example):

    print FILE unless ( $_ =~ /^\Q$std\E\b/ );

    When you did open ">$stdInfo" you truncated the file, so if a print subsequently fails, you have permanently lost information from the $stdInfo file. You may not even know about it because you are not checking the return code from print or close. As already pointed out, opening in append mode seems best. If you must rewrite the whole file, write to a temporary file first, then rename after you are sure the rewrite has been successful.

Re: appending to a file
by arden (Curate) on Feb 26, 2004 at 05:21 UTC
    First off, what error are you getting? Just saying that it's "not working for me" isn't really helping us to help you. Second off, if you are wanting to append names onto the end of a file, you should open FILE the second time like open(FILE, ">>$stdInfo")... and then print to FILE if the new name isn't already in your array. But, I wouldn't use an array, I'd use a hash, it's easier to check if it exists();. Finally, in your code, you don't have any method to actually add any names to the file, you don't prompt for anything but a number for a student, what's that supposed to relate to?

    - - arden.

Re: appending to a file
by Anonymous Monk on Feb 26, 2004 at 06:37 UTC

    Sometimes I just love doing homework :) If you plan on using this for a class, you'd better make sure you understand everything I've used. You wouldn't want a prof to ask "what does _that_ do?" and you end up blubbering a "I don't know what _that_ does".

    #!c:/perl/bin/perl -w $|++; use strict; use Fcntl ':flock'; print "Enter new student's name: "; chomp( my $student = <STDIN> ); open my $fh, '+<', 'students.dat' or die "open failed: $!"; flock $fh, LOCK_EX or die "flock failed: $!"; my $found = 0; while (<$fh>) { $found = 1 if /^\Q$student\E$/i; } print $fh $student, "\n" unless $found; close $fh;
      Each line of the input file is probably going to look something like:

      John Doe\n

      And your regex: /^\Q$student\E$/ will never match any line in that file, because it doesn't allow for the trailing newline. Thus, $student will always get printed, even if the name already exists. F


      Dave

        Did you even try running my script? If you had, you'd have seen that it works just fine. Notice the anchor I used. '$', not '\z'. So the match works just fine thank you.