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

Hi all, How can i alter this code so that it only writes to first line in the file:
# header of file where info gathered 0.123 0.654 - so write before these values only 0.987 0.678
if ($aa =~ /LEU\b/) {s/ (.*)/$z3leu $z2leu $z1leu $1/}

Replies are listed 'Best First'.
Re: substitutions on a single line
by Corion (Patriarch) on Apr 13, 2004 at 15:57 UTC

    If you only want to change certain lines in a file, also take a look at Tie::File, which makes this very easy:

    use strict; use Tie::File; tie @lines, 'Tie::File', $filename or die "Couldn't open $filename : $!"; for my $line (@lines) { if ($line =~ /LEU\b/) { s/ (.*)/$z3leu $z2leu $z1leu $1/ } };

    That's it.

    For an alternative, you could run Perl as a pipeline by redirecting the output of the following into a new file:

    perl -pe "/LEU\b/ and s/ (.*)/$z3leu $z2leu $z1leu $1/"
Re: substitutions on a single line
by tachyon (Chancellor) on Apr 13, 2004 at 15:41 UTC
Re: substitutions on a single line
by davido (Cardinal) on Apr 13, 2004 at 15:41 UTC
    Assuming you've got your while loop set up right and you're doing inline editing... and that the only thing you need is to perform an edit on the first line, you could modify your "if" statement like this:

    $. == 1 && $aa =~ /LEU\b/ && s/ (.*)/$z31eu $z2leu $z1leu $1/;

    That way, only when $. (the filehandle line counter) equals zero (the first line of the file) you will actually modify the line. The rest of your iterations through the fils you'll basically skip the code that performs the substitution.

    Remember, of course, that you do have to write each line anew. The most common strategy is to open the input file, open a temporary output file, read line by line from the input file as you write line by line to the output file. You must do this for every line of the file. And on the first line (in your case) you'll also perform additional modifications to the data. Finally, you close both files, and rename the temp file to the name of your input file.

    Update: Changed $. == 0 to $. == 1 to correct the error pointed out by halley.


    Dave

      $. is 1-based. Before reading, it is undef. After reading a line, it is 1. Unless you assign to it, it is never actually 0, and although undef == 0, that's not what you want to write here.

      --
      [ e d @ h a l l e y . c c ]

      i have been trying your suggestion but with no success. This is what i have, the while loop should read each individual line?:
      while (<FILE1>) { ($hash, $input, $for, $aa) = split( /\s+/, $_) if /^\# \input\b.*/; $. == 1 && $aa =~ /LEU\b/ && s/ (.*)/$z31eu $z2leu $z1leu $1/; print output "$_"; }
        For one thing I'm not sure what $z31eu, $z21eu, and $z11eu contain, and I also don't know that your regexen are actually matching what you expect them to.

        At any rate, I would start lacing your program's logic with prints to see which step fails, and then look at the contents of the suspect variables at that point to see why your logic is failing.


        Dave

Re: substitutions on a single line
by blue_cowdawg (Monsignor) on Apr 13, 2004 at 15:48 UTC

    Maybe I'm getting senile before my time here, but I am not sure what you are asking.

    Looking at the regex you are the first change I would propose would be the use of s/\s+(.*)$/$z3leu $z$leu $z1leu $1/ in your substitution. I set up a quick test that looks like:

    $done=0; while (<DATA>){ $_ =~ s/\s+(.*)$/$1/ unless $done; print; $done=1; } __END__ 0.123 0.654 - so write before these values only 0.987 0.678
    just to prove out the regex. However, I don't know what those other variables are about.

    Note that I have a "flag" set to make it only act on the first line.

    I hope this helps, but I'm not 100% sure what you are after...