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

Hello all,

I've only been using perl for about 3 months now, so be gentle with me.

I'm trying to remove a section of a certain line in a file.

Code:

use warnings; $file = $ARGV[0]; open (FILE,$file) or die "Can't open $file!"; while (<FILE>) { $line = $_; chomp $line; if ($line =~ /\>/) { @modify_line = split(/\s/,$line); $changed_line = shift(@modify_line); $line=$changed_line; print "$line\n"; } } close FILE;

The code is working in that the desired section of the line is removed, but the file itself remains unaffected. The result is merely printed to the screen.

How do I get the result to change the line in the file itself, not just print to the screen?

Replies are listed 'Best First'.
Re: How do I modify a line within the file itself?
by choroba (Cardinal) on Jul 08, 2015 at 21:00 UTC
    You can use the -i perl flag to change the file "in place" (see perlrun). You have to print all the lines, though, not only the changed one, and process the input with the diamond operator <> instead of creating your own file handle.
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: How do I modify a line within the file itself?
by jeffa (Bishop) on Jul 08, 2015 at 21:11 UTC

    As others have already explained, you have to write the data back to the file, either by using in-place editing or just manually doing it yourself:

    use strict; use warnings; my $file = shift; open FILE, $file or die "Can't read from $file!\n"; my @lines; while (my $line = <FILE>) { if ($line =~ /\>/) { push @lines, (split( /\s/, $line ))[0] . "\n"; } else { push @lines, $line; } } close FILE; open FILE, '>', $file or die "Can't write to $file!\n"; print FILE @lines; close FILE;

    Or using something like Tie::File if your memory constraints are not preventing you:

    use strict; use warnings; use Tie::File; my $file = shift; tie my @lines, 'Tie::File', $file or die "Can't read from $file\n"; for (0 .. $#lines) { if ($lines[$_] =~ /\>/) { $lines[$_] = (split( /\s/, $lines[$_] ))[0] . "\n"; } }

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
Re: How do I modify a line within the file itself?
by 1nickt (Canon) on Jul 08, 2015 at 23:44 UTC

    You should always use strict. It will save your life. Start now.

    You should always open files with three arguments.

    You should make your code as readable as possible, including use of $_ as the default input.

    use strict; use warnings; my $file = $ARGV[0]; open(my $fh, "<", $file) or die "Can't open $file: $!"; while ( <$fh> ) { chomp; # $_ is default input if ( /\>/ ) { # $_ is still default input, # match is default operation my @modify_line = split( /\s/ ); # $_ is still default input my $line = $modify_line[0]; # if you are going to use an array print $line; }

    Not that you should do it this way. Use File::Slurp::Tiny.

    Remember: Ne dederis in spiritu molere illegitimi!

      Not that you should do it this way. Use File::Slurp::Tiny.

      I wouldn't recommend anything starting with "File::Slurp"

      Path::Tiny is what I'd recommend

        I wouldn't recommend anything starting with "File::Slurp"

        That's an incredibly ignorant thing to say. File::Slurp is over 20 years old and is a dependency in more than 500 CPAN distributions. Do a little research on Uri Guttman.

        Leon Timmermans, one of the prominent Perl contributors of the new generation, author of File::Slurp::Tiny, is not exactly known for unreliable code, either.

        To the OP: some of what you will receive here in response to your questions is utter crap. Do your own due diligence and evaluate the advice you get in other parts of the Perl realm ...

        Remember: Ne dederis in spiritu molere illegitimi!
Re: How do I modify a line within the file itself?
by Anonymous Monk on Jul 08, 2015 at 20:58 UTC

    Files and I/O in perlintro shows you how to print to files. Similar to the input file, open the output file (using a different file handle) before the loop, print to the file inside the loop, and close the file after the loop.

Re: How do I modify a line within the file itself?
by sierpinski (Chaplain) on Jul 08, 2015 at 21:04 UTC

    Even though this is perlmonks, I'd likely use sed to accomplish replacing in-line text in a file. Granted I'm not a sed expert -- barely a sed beginner, I'd look into that instead.

    Is there a requirement to use Perl, or some other reason not to use a (usually) built-in tool like sed?

Re: How do I modify a line within the file itself?
by Anonymous Monk on Jul 08, 2015 at 23:58 UTC

    So Path::Tiny it like autodies for you :)

    #!/usr/bin/perl -- use strict; use warnings; use Path::Tiny; my( $inFile, $outFile ) = @ARGV; my $outfh = path( $outFile )->openw_raw; my $infh = path( $infile )->openr_raw; while( my $line = <$infh>){ chomp $line; if ($line =~ /\>/) { my @modify_line = split(/\s/,$line); $line = $modify_line[0]; } print $outfh "$line\n"; } close $infh; close $outfh;

      Wow, that's a lot of code. The whole purpose of using an external library is to reduce how much code you have to write!

      Try File::Slurp:

      #!/usr/bin/env perl -w use strict; use File::Slurp 'edit_file_lines'; my $inFile = shift; edit_file_lines { m/\>/ && s/(\S+)\s.*/$1/ } $inFile; __END__

      .... neat, huh? For an in-place edit, that's the way to go.

      When I need to do something more with the lines in the file, I usually skip the full monty and go with File::Slurp::Tiny, but in this case that takes a little more coding since you have to build up an array to pass to its write_file method, and you need to create an output file:

      #!/usr/bin/env perl -w use strict; use File::Slurp::Tiny qw/ read_lines write_file /; my ( $inFile, $outFile ) = @ARGV; my @keep; foreach my $line ( read_lines($inFile, chomp => 1) ) { push ( @keep, ($line =~ /\>/ ? (split(/\s/, $line))[0] : $line)); } write_file( $outFile, join("\n", @keep, '') );
      Remember: Ne dederis in spiritu molere illegitimi!

        I thank you for the examples

        Wow, that's a lot of code. The whole purpose of using an external library is to reduce how much code you have to write!

        Didn't you notice the reduction? There is no 3 argument open , no "or die" verbosity? I think thats neat

        ... edit_file_lines .... neat, huh? For an in-place edit, that's the way to go.

        Did you know that reads the whole file into memory? It limits the size of files you can edit to the amount of RAM you have (and perl has access to)

        That /\>/ hints to me the OP might be dealing with gigabyte sized files, probably a good idea to avoid slurping

        When I need to do something more with the lines in the file, I usually skip the full monty and go with File::Slurp::Tiny, but in this case that takes a little more coding since you have to build up an array to pass to its write_file method, and you need to create an output file:

        That has the same issue, it read whole file into memory/an array, duplicate this array, write it out ; Too much memory requirement based on size of file.

Re: How do I modify a line within the file itself?
by 1nickt (Canon) on Jul 16, 2015 at 11:57 UTC

    Accuracy compels me to point out that within a week or so after I recommended File::Slurp::Tiny in this thread, its author released a new version with a "USE OF THIS MODULE DISCOURAGED" message at the top of the documentation.

    I withdraw my recommendation, even though I have personally never had a problem using the module.

    The way forward always starts with a minimal test.
Re: How do I modify a line within the file itself?
by locked_user sundialsvc4 (Abbot) on Jul 09, 2015 at 00:57 UTC

    Kindly let me also offer the following bit of “battlefield experience,” which by-the-way will also serve to make your task much easier:

    Never actually try to modify a [flat ...] file “in place!”

    Instead, always write such logic so that it reads the existing file as input, and writes “the next ‘generation’ of that file” as output.   I-f the operation succeeds, you can now rename the files ... perhaps even using a scheme like the logrotate command does, or, what-the-hell, just using logrotate ... so that both the “old” and the “new” file remain.

    The advantages are obvious:   “if something goes wrong, you’re not scroo-oo-ood.”   You can just run the command again.   And if the defect does not rear its ugly head until some time later ... as ugly defects so-often do ... you still might not be scroo-oo-ood.   The edits that you made were non-destructive.

    And while we are on this subject, here is another battlefield suggestion:   “if the files in question are not of some titanic size, consider turning the directory-in-question into a git repository.”