How do I make the STDIN in the Array stop? (PERL)

2.3k Views Asked by At

My @array will not stop taking in STDIN...

my @array = undef;
while (@array = undef){
    @array = <STDIN>;
    for (@array[x]=5){
        @array = defined;
    }
}
2

There are 2 best solutions below

12
zdim On BEST ANSWER

As clarified, limit the STDIN to five lines

use warnings;
use strict;
use feature 'say';

my @input;

while (<STDIN>) {
    chomp;
    push @input, $_;
    last if @input == 5;
}

say for @input;

There are other things to comment on in the posted code. While a good deal of it is cleared up in detail in Dave Cross answer, I'd like to address the business of context when reading from a filehandle.

The "diamond" operator <> is context-aware. From I/O Operators (perlop)

If a <FILEHANDLE> is used in a context that is looking for a list, a list comprising all input lines is returned, one line per list element. It's easy to grow to a rather large data space this way, so use with care.

In the usual while loop the <> is in the scalar context

while (my $line = <$fh>)

and it is the same with while (<$fh>) since it assigns to $_ variable, a scalar, by default.

But if we assign to an array, say from a filehandle $fh with which a file was opened

my @lines = <$fh>;

then <> operator works in the list context. It reads all lines until it sees EOF (end-of-file), at which point it returns all lines, which are assigned to @lines. Remember that each line has its newline. You can remove them all by

chomp @lines;

since chomp works on a list as well.

With STDIN this raises an issue when input comes from keyboard, as <> waits for more input since EOF isn't coming on its own. It is usually given as Ctrl+D on Unixy systems (Ctrl+Z on Windows).

So you can, in principle, have @array = <STDIN> and quit input with Ctrl+D but this may be a little awkward for input expected from keyboard, as it mostly implies the need for line by line processing. It is less unusual if STDIN comes from a file,

script.pl < input.txt

or a pipe on the command line

some command with output | script.pl

where we do get an EOF (courtesy of EOT).

But I'd still stick to a customary while when reading STDIN, and process it line by line.


  The Ctrl+D is how this is usually referred to but one actually types a low-case d with Ctrl. Note that Ctrl and c (labeled as Ctrl+C) does something entirely different; it sends the SIGINT signal, which terminates the whole program if not caught.

0
Dave Cross On
my @array = undef;
while (@array = undef){

These two lines don't do what (I assume) you think they are doing.

my @array = undef;

This defines an array with a single element which is the special value undef. I suspect that what you actually wanted was:

my @array = ();

which creates an empty array. But Perl arrays are always empty when first created, so this can be simplified to:

my @array;

The second line repeats that error and adds a new one.

while (@array = undef) {

I suspect you want to check for an empty array here and you were reaching for something that meant something like "if @array is undefined). But you missed the fact that in Perl, assignment operators (like =) are different to comparison operators (like ==). So this line assigns undef to @array rather than comparing it. You really wanted @array == undef - but that's not right either.

You need to move away from this idea of checking that an array is "defined". What you're actually interested in is whether an array is empty. And Perl has a clever trick that helps you work that out.

If you use a Perl array in a place where Perl expects to see a single (scalar) value, it gives you the number of elements in the array. So you can write code like:

my $number_of_elements = @an_array;

The boolean logic check in an if or while condition is a single scalar value. So if you want to check if an array contains any elements, you can use code like this:

if (@array) {
  # @array contains data
} else {
  # @array is empty
}

And to loop while an array contains elements, you can simply write:

while (@array) {
  # do something
}

But here, you want to do something while your array is empty. To do that, you can either invert the while condition logic (using ! for "not"):

while (!@array) {
  # do something
}

Or you can switch to using an until test (which is the opposite of while):

until (@array) {
  # do something
}

I'm going to have to stop there. I hope this gives you some insight into what is wrong with your code. I'm afraid that this level of wrongness permeates the rest of your code too.