in reply to Re: Deleting a line out of text file
in thread Deleting a line out of text file

Thanks to all. Here is the direction I wanted to go but this wipes out my whole file and just keeps the line I changed: Can someone tell me how I can fix this?
my $fil = 'file.txt'; open(DATA, "$fil") || die "Can not open: $!\n"; my @dat = (<DATA>); close(DATA); open(DATA, ">$fil") || die "cant write: $!\n"; foreach (@dat) { if($_ =~ /number/) { s/number/NEWWORD/; print DATA $_; } } close(DATA);

Replies are listed 'Best First'.
Re: Re: Re: Deleting a line out of text file
by dga (Hermit) on Aug 13, 2003 at 17:35 UTC

    You need to print out all the other lines also.

    If you want to edit a line and leave it in the file then just get rid of the if.

    ... foreach (@dat) { s/number/NEWWORD/; print DATA $_; } close(DATA);

    This will change the lines that need changing and print everything into the file.

    There is another risk with this method that if the program dies before getting the file printed back out your original file which was erased on the second open will not have the complete data. This is what the backup options cover you against.

    This will do the translation and leaves a backup file in this case named file.txt.bak.

    perl -pi.bak -e 's/number/NEWWORD/;' file.txt

    The -p says to print every line, the -i.bak says make a backup file by adding .bak to the input file name, -e says to run the next argument as a perl script. The substitute only happens if the pattern matched so there is no need for an if unless you want to locate one pattern and then replace another pattern with yet a different replacement.

      Here's another way, using grep to exclude lines matching the unwanted pattern as they are read in from the file:
      ... use strict; my $file = 'data_file.txt'; my $bad_pattern = '019'; open my $in_fh, "<$file" or die "can't open $file to read"; my @good_lines = grep { !/$bad_pattern/ } <$in_fh>; close $in_fh; open my $out_fh, ">$file" or die "can't open $file to write"; print $out_fh $_ foreach @good_lines; close $out_fh;
      thanks it now works with what you gave me:
      foreach (@dat) { s/number/NEWWORD/; print DATA $_; } close(DATA);
      Not sure I can use the perl command line backup example you gave me:
      perl -pi.bak -e 's/number/NEWWORD/;' file.txt
      because this is in a cgi web page script. Can I do some backup work as you suggested with this?
      foreach (@dat) { s/number/NEWWORD/; print DATA $_; } close(DATA);

        With a CGI script, you would have to manage the files yourself. And actually if this is going to be running on a server where you might ever have 2 people use this then you need to do some file management.

        The basic procedure is to write the data into a new file then rename the file to the old name and use locking to prevent 2 people from trying to do that at the same time.

        On Unixes you can use sysopen to pass O_CREAT|O_EXCL|O_WRONLY flags to the open which will fail if the temporary file exists already. You have to catch the failure and retry in a bit (like 1 second).

        The other option is to use flock to do locking on the original file while you do the updating and unlock it when you are done. This has an option to wait but people don't use it because if the lock is left alive then all web accesses will wait while the user sits there looking at a blank web page. So this locking is usually checked non blocking which mirrors the sysopen behaviour. I think that flock is the best(only?) answer on windows and as such is more portable than sysopen which by definition is 'less portable'. Also the create exclusively is automic on Unix/Linux etc but I don't know on Windows, if its even available. Also, any one who has access to the file not via the CGI is free to ignore the locking completely via either method. Flocks go away if the process holding them dies whereas temp files do not so if you can arrange a exit/die on failire then the file gets unlocked.

        In Summary, if you have more than 1 person ever do this, your file will turn up empty sooner or later.