user001
user001

Reputation: 1848

How can I read from both STDIN and files passed as command line arguments without using `while(<>)`?

This post demonstrates how one can read from STDIN or from a file, without using the null filehandle (i.e., while(<>)). However, I'd like to know how can one address situations where input may come from files, STDIN, or both simultaneously.

For instance, the <> syntax can handle such a situation, as demonstrated by the following minimal example:

$ echo -e 'a\nb\nc' | \
  while read x; do echo $x > ${x}".txt"; done; echo "d" | \
  perl -e "while(<>) {print;}" {a,b,c}.txt -
a
b
c
d

How can I do this without using while(<>)?

I want to avoid using <> because I want to handle each file independently, rather than aggregating all input as a single stream of text. Moreover, I want to do this without testing for eof on every line of input.

Upvotes: 0

Views: 830

Answers (3)

user4401178
user4401178

Reputation:

Here is an idea based on Tim's that checks if STDIN has something to read (NON BLOCKING STDIN). This is useful if you don't really care about a user entering input manually from STDIN yet still want to be able to pipe and redirect data to the script.

File: script.pl

#!/usr/bin/env perl 

use IO::Select;

$s = IO::Select->new();
$s->add(\*STDIN);
if ($s->can_read(0)) { push @ARGV, "/dev/stdin"; } 

for (@ARGV) {
    open(IN, "<$_") || die "** Error opening \"$_\": $!\n";
    while (<IN>) {
        print $_
    }
}

$> echo "hello world" | script.pl
hello world

$> script.pl < <(echo "hello world")
hello world

$> script.pl <(echo "hello world")
hello world

$> script.pl <<< "hello world"
hello world

$> script.pl
$>

Upvotes: 1

ikegami
ikegami

Reputation: 385764

This was already answered by the Answer to which the question links.

@ARGS = '-' if !@ARGV;

for my $qfn (@ARGV) {
    open($fh, $qfn);

    while (<$fh>) {
       ...
    }
}

Upvotes: 0

Tim Pierce
Tim Pierce

Reputation: 5664

If you want to handle each file independently of the others, you should loop over the arguments that have been given and open each file in turn:

for (@ARGV) {
    open(my $fh, '<', $_) || die "cannot open $_";
    while (<$fh>) {
        ... process the file here ...
    }
}
# handle standard input
while (<STDIN>) {
    ...
}

Upvotes: 1

Related Questions