varatis
varatis

Reputation: 14740

How to remove one line from a file using Perl?

I'm trying to remove one line from a text file. Instead, what I have wipes out the entire file. Can someone point out the error?

removeReservation("john");

sub removeTime() {
    my $name = shift;

    open( FILE, "<times.txt" );
    @LINES = <FILE>;
    close(FILE);
    open( FILE, ">times.txt" );
    foreach $LINE (@LINES) {
        print NEWLIST $LINE unless ( $LINE =~ m/$name/ );
    }
    close(FILE);
    print("Reservation successfully removed.<br/>");
}

Sample times.txt file:

04/15/2012&08:00:00&bob
04/15/2012&08:00:00&john

Upvotes: 8

Views: 53997

Answers (5)

Serious Angel
Serious Angel

Reputation: 1555

Just in case someone wants to remove all lines from a file.

For example, a file (4th line is empty; 5th line has 3 spaces):

t e st1
test2 a
  e

   
aa 
    bb bb
test3a
cc

To remove lines which match a pattern some might use:

# Remove all lines with a character 'a'
perl -pi -e 's/.*a.*//' fileTest && sed -i '/^$/d' fileTest;

The result:

t e st1
  e
   
    bb bb
cc

Related:

perl -h
    # -p                assume loop like -n but print line also, like sed
    # -i[extension]     edit <> files in place (makes backup if extension supplied)
    # -e program        one line of program (several -e's allowed, omit programfile)

sed -h
    # -i[SUFFIX], --in-place[=SUFFIX]
    #                edit files in place (makes backup if SUFFIX supplied)

Reference 1, Reference 2

Upvotes: 0

Daniel C. Sobral
Daniel C. Sobral

Reputation: 297195

perl -ni -e 'print unless /whatever/' filename

Upvotes: 23

David W.
David W.

Reputation: 107040

Oalder's answer is correct, but he should have tested whether the open statements succeeded or not. If the file times.txt doesn't exist, your program would continue on its merry way without a word of warning that something terrible has happened.

Same program as oalders' but:

  1. Testing the results of the open.
  2. Using the three part open statement which is more goof proof. If your file name begins with > or |, your program will fail with the old two part syntax.
  3. Not using global file handles -- especially in subroutines. File handles are normally global in scope. Imagine if I had a file handle named FILE in my main program, and I was reading it, I called this subroutine. That would cause problems. Use locally scoped file handle names.
  4. Variable names should be in lowercase. Constants are all uppercase. It's just a standard that developed over time. Not following it can cause confusion.
  5. Since oalders put the program in a subroutine, you should pass the name of your file in the subroutine as well...

Here's the program:

#!/usr/bin/env perl 

use strict; 
use warnings; 

removeTime( "john", "times.txt" ); 

sub removeTime { 
    my $name      = shift;
    my $time_file = shift;

    if (not defined $time_file) {
        #Make sure that the $time_file was passed in too.
        die qq(Name of Time file not passed to subroutine "removeTime"\n);
    }

    # Read file into an array for processing
    open( my $read_fh, "<", $time_file )
       or die qq(Can't open file "$time_file" for reading: $!\n); 

    my @file_lines = <$read_fh>; 
    close( $read_fh ); 

    # Rewrite file with the line removed
    open( my $write_fh, ">", $time_file )
        or die qq(Can't open file "$time_file" for writing: $!\n);

    foreach my $line ( @file_lines ) { 
        print {$write_fh} $line unless ( $line =~ /$name/ ); 
    } 
    close( $write_fh ); 

    print( "Reservation successfully removed.<br/>" ); 
}

Upvotes: 8

Dave Cross
Dave Cross

Reputation: 69244

This is in the FAQ.

How do I change, delete, or insert a line in a file, or append to the beginning of a file?

It's always worth checking the FAQ.

Upvotes: 4

oalders
oalders

Reputation: 5279

It looks like you're printing to a filehandle which you have not yet defined. At least you haven't defined it in your sample code. If you enable strict and warnings, you'll get the following message:

Name "main::NEWLIST" used only once: possible typo at remove.pl line 16.

print NEWLIST $LINE unless ($LINE =~ m/$name/);

This code should work for you:

#!/usr/bin/env perl 

use strict; 
use warnings; 

removeTime( "john" ); 

sub removeTime { 
    my $name = shift; 

    open( FILE, "<times.txt" ); 
    my @LINES = <FILE>; 
    close( FILE ); 
    open( FILE, ">times.txt" ); 
    foreach my $LINE ( @LINES ) { 
        print FILE $LINE unless ( $LINE =~ m/$name/ ); 
    } 
    close( FILE ); 
    print( "Reservation successfully removed.<br/>" ); 
}

A couple of other things to note:

1) Your sample code calls removeReservation() when you mean removeTime()

2) You don't require the round brackets in your subroutine definition unless your intention is to use prototypes. See my example above.

Upvotes: 8

Related Questions