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

Hi everyone, I have 2 open input files F0 and F1 and trying to read the second (F1) which contains IPs only but get the first instead when using print "$_ at line 9 3    PORT    state    protocol I m suppored to get and IP as in 1.0.131.74 what s wrong
here I read a second file F1 (line 9) while within a while loop for the second (line 9) and first file F0 (line 3)
I have read
the open function http://perldoc.perl.org/functions/open.html https://www.perltutorial.org/perl-open-file/ https://perldoc.perl.org/functions/open
the read file https://www.perltutorial.org/perl-read-file/
Open and read https://perlmaven.com/open-and-read-from-files
I have double checked the program command line arguements perl code.pl port.txt IP.txt output.txt here are the
program
open(F0, $ARGV[0]); open(F1, $ARGV[1]); open(F2, ">$ARGV[2]"); $line_no=$line_stop=0; while (<F0>) { while (s/^[\ \t]//g) {}; while (s/[\ \t]$//g) {}; s/\r\n//;s/\t+/\t/;chomp; /^[0-9]+/; $line=$'; $line_no=$&; while (<F1> && ($line_stop++ < $line_no)) { while (s/^[\ \t]//g) { +}; while (s/[\ \t]$//g) {}; s/\r\n//;s/\t+/\t/;chomp; print "$_\n";} print F2 $IP, "\t$line\n" if /[0-9]+\//; } close F0; close F1; close F2;
IP file
1.0.129.197 1.0.131.49 1.0.131.74 1.0.138.143 1.0.138.154 1.0.139.72
port file
3 PORT state protocol 3 80/tcp closed http 3 443/tcp closed https 3 8080/tcp open http-proxy 5 80/tcp open http 5 443/tcp filtered https 5 8080/tcp filtered http-proxy
can someone tell me why I m reading from the wrong filehandle
Thanks for you help

Replies are listed 'Best First'.
Re: reading the wrong input file out of 2 opened file
by choroba (Cardinal) on Jan 24, 2022 at 15:21 UTC
    while (<F0>)
    reads a line from F0 and assigns it to $_, and stops the loop unless the value is defined.

    On the other hand,

    while (<F1> && ($line_stop++ < $line_no))
    reads a line from F1, but doesn't assign it anywhere, and would stop the loop if the value was false.

    See I/O Operators for details.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: reading the wrong input file out of 2 opened file
by marto (Cardinal) on Jan 24, 2022 at 15:26 UTC
Re: reading the wrong input file out of 2 opened file
by Fletch (Bishop) on Jan 24, 2022 at 16:08 UTC

    And I don't think it's been mentioned yet but nesting your while loops reading like that doesn't make much since sense. You're going to read the first line from FO, then you're going to read all the lines from F1 (modulo the problems already mentioned there). The next time through it would try and read the next line from F0 but when it tried to read from F1 again that's going to still be at the end of the file and not do anything useful.

    That being said this whole thing's a mess between the formatting and the logic; I don't have the time (nor inclination, honestly) to untangle it. You should stop and take a step back and think what you're doing and change your approach. But as I said, I can't make heads nor tails of what you're attempting to do so I don't really have any suggestion what you should be doing (like what data structure you'd want to parse the shorter/smaller file into to consult against as you read through the larger one).

    Edit: ENOCAFFEINE. A word.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: reading the wrong input file out of 2 opened file
by Marshall (Canon) on Jan 24, 2022 at 16:07 UTC
    You should always be using use strict; use warnings;. The blizzard of while statements and substitutions is very confusing to me.

    while (<F1> && ($line_stop++ < $line_no)) { while (s/^[\ \t]//g) {} };
    The reads a line from F1 and puts it into $_ which is thrown away, but if such a line was read (the read operation logically succeeded), then the statement compares $line_stop<$line_no. But $line_stop hasn't been declared yet, so this won't work. And we have the problem that the line itself is not available for processing. The second while loops until it cannot remove any more spaces or tabs at the beginning of the line. The while loops and the /g modifier is completely unnecessary. s/^\s+//; would be sufficient, but none of your lines have extra white space at the beginning of the line, so that won't work either.

    Your code is so confusing, I have no idea what it is really supposed to do. But I took a wild ass guess based upon just looking at the input files. Code below which uses a tricky feature of opening a Perl variable like an input file so that I can show everything as a single runnable Perl program.

    Maybe back up and explain what you are trying to do?

    use strict; use warnings; my $IP_file = << 'END'; 1.0.129.197 1.0.131.49 1.0.131.74 1.0.138.143 1.0.138.154 1.0.139.72 END my $Port_file = << 'END'; 3 PORT state protocol 3 80/tcp closed http 3 443/tcp closed https 3 8080/tcp open http-proxy 5 80/tcp open http 5 443/tcp filtered https 5 8080/tcp filtered http-proxy END my $output_file; open my $IP, "<", \$IP_file or die "unable to open IP file for +reading $!"; open my $PORT, "<", \$Port_file or die "unable to open port file fo +r reading $!"; open my $OUT, ">", \$output_file or die "unable to open output file +for writing $!"; <$PORT>; # throw away first line ion port file while (defined (my $ip_line =<$IP>) and defined (my $port_line = <$POR +T>)) { chomp $ip_line; $port_line =~ s/^\d+\s+/$ip_line /; print "$port_line"; } __END__ Prints: 1.0.129.197 80/tcp closed http 1.0.131.49 443/tcp closed https 1.0.131.74 8080/tcp open http-proxy 1.0.138.143 80/tcp open http 1.0.138.154 443/tcp filtered https 1.0.139.72 8080/tcp filtered http-proxy
      The reads a line from F1 and puts it into $_

      wrong

        You are correct. This is an artifact of having the logical statement in the conditional. while (<FH>){} does assign the line to $_. However, while (<FH> and some condition){} doesn't assign the read line to $_ only the "truthiness" of whether a line was actually read or not is used (the line itself is thrown away). Ok, we have found yet another reason why this odd looking while statement won't work. while (defined (my $line =<FH>) and some condition){} is perhaps better. It is possible to assign to $_ (left hand side), but I seldom do that. This whole idea of an "and" or "&&" statement in the while condition looks dubious to me.
Re: reading the wrong input file out of 2 opened file
by talexb (Chancellor) on Jan 24, 2022 at 17:34 UTC

    Just to throw some TMTOWTDI in .. you could also use Tie::File to read from the files; that way, you could read through the inner file without having to rewind. Then again, it also looks like you could just load the files into data structures once, then figure stuff out by looking at the structures.

    Alex / talexb / Toronto

    Thanks PJ. We owe you so much. Groklaw -- RIP -- 2003 to 2013.

Re: reading the wrong input file out of 2 opened file
by cavac (Prior) on Jan 26, 2022 at 09:47 UTC

    What happened to strict and warnings in your code? Also, i recommend that you use Carp. The "English" module also makes your code clearer. Avoid the implicit variable $_ - it is (in my opinion) the spawn of evil and should be avoided at all costs to make code easier to read.

    #!/usr/bin/env perl use strict; use warnings; use Carp; use English;

    open(F0, $ARGV[0]); open(F1, $ARGV1); open(F2, ">$ARGV2");

    Urgh, there are so many things wrong with that, it gives me an instant headache. First of all, do not use plain file handles, use variables. Use three-argument open(). Check the return value of open(). Use multiple lines. Put the ARGV stuff into named variables to make the code clearer. Use proper variable names for the filehandle, so you know later in the code which handle does what.

    my ($ipfname, $portfname, $resultfname) = @ARGV; open(my $ipfh, '<', $ipfname) or croak($ERRNO); open(my $portfh, '<', $portfname) or croak($ERRNO); open(my $resultfh, '>', $resultfname) or croak($ERRNO);

    I can't really make out what the rest of your code is trying to do. I'll suggest you implement the recommendations by me and the others who have already replied to your question and see if that helps. You can always come back with a new question, but please do at least the following:

    1. Explain what your code is trying to do. Adding an example output (can be edited by hand) is very helpful.
    2. Implement our recommendations as far as possible. "use strict" and "use warnings" are pretty much a requirement these days.
    3. Make your code more readable. One command per line, proper indentation.
    4. Add comments. Especially comment on the regular expressions. Yes, we can "decode" them, but it's easier if you already tell us what they are supposed to do. Makes the code easier to understand and allows us to check if the regex actually does what you think it should do.
    5. Use variables with names that hint at their intended purpose.
    6. Check the return value of open().
    7. Show us your error messages (if any).

    Most of us have limited time to understand questions and come up with good answers. The best way for us to help you is for you to help us in providing a good question that is easy to read, easy to understand and has readable example code (and example data, if applicable).

    I can only speak for this from my own point of view, but say there are three new SoPW questions. Two of them are easy to understand and one would take an hour just to understand what the example code might try to do. I'm not talking about how complicated itis to come up with a solution, just how hard it is to even understand what the problem is. In this case i will probably work on the two easy questions and ignore the confusing one.

    perl -e 'use Crypt::Digest::SHA256 qw[sha256_hex]; print substr(sha256_hex("the Answer To Life, The Universe And Everything"), 6, 2), "\n";'
Re: reading the wrong input file out of 2 opened file
by perl_boy (Novice) on Feb 01, 2022 at 23:50 UTC