Search code examples
perlcountererasestring

Perl: Erase empty lines and save in a new file


I am trying to write a script which will count and erase empty lines from a file and save the changes in a new file:

if (@ARGV != 2) {
  print "Usage: $0 infile outfile\n";
  exit;
}
$infile = @ARGV[0];
$outfile = @ARGV[1];
open($old, "<$infile");
open($new, ">$outfile");
@mass = <$old>;
foreach $newc(@mass) {
    $counter++;
    if ($_ =~ /^$/) {
        print "blank line found in $old at line number $counter\n";
        print $new;
    }
}
close($new);
close($old);

But it's not working. Where am I going wrong?


Solution

  • Here's another option:

    use strict;
    use warnings;
    
    @ARGV == 2 or die "Usage: $0 infile outfile\n";
    
    open my $fhIN,  '<', $ARGV[0] or die $!;
    open my $fhOUT, '>', $ARGV[1] or die $!;
    
    while (<$fhIN>) {
        if (/\S/) {
            print $fhOUT $_;
        }
        else {
            print "Blank at line $.\n";
        }
    }
    

    As amon showed, you can iterate over your file's lines without first reading them into an array. This script also takes advantage of $., which contains the file's current line number. The regex /\S/ checks for any non-whitespace characters in the line, as this indicates a non-blank line. If /\S/ is true, it writes the line to outfile, else it prints the blank-line notification.

    The file handles are lexically scoped in the three-argument form of open (the preferred method), so the files will automatically close at the script's end.


    You can even go a step further and take advantage of STDIN, STDOUT and STDERR for maximum flexibility and usefulness.

    use strict;
    use warnings;
    
    while (<>) {
        if (/\S/) {
            print;
        }
        else {
            print STDERRR "Blank at line $.\n";
        }
    }
    

    Then just use

    script.pl file.in >file.out
    

    instead of

    script.pl file.in file.out
    

    but it also allows you to do stuff like

    prog1 | script.pl | prog2