简体   繁体   中英

can a perl script be written to receive data from any of (1) file, (2) stdin, (3) redirect?

Several unix utilities, such as fmt, head, and cat, can receive data in any of 3 ways: a filename; a pipe from standard input; or a redirect "<". For instance:

printf '%b' 'dog \ncat \nrat\n' > dogcatrat
fmt dogcatrat
cat dogcatrat  | fmt
fmt < dogcatrat

Can one write a perl script that will behave with the same versatility? Or is there a good reason not to attempt this? And is "pipe from standard input" the right way to refer to the line of code that starts with cat?

I want to write myfmt.pl, to be used in any of these three ways.

The ARGV special filehandle will do this by default. It is also the handle used by readline (aka the <> and <<>> operators) when not given a handle. So this is actually pretty common in Perl scripts.

#!/usr/bin/env perl
use 5.022;
use warnings;
while (my $line = <<>>) {
  # $line from one of the filenames passed as an argument, otherwise STDIN
  # $ARGV is the current filename, or - when reading from STDIN
}

You can use the <> operator instead to support older versions of Perl, but the <<>> operator added in Perl 5.22 is a better option for this task if available, because the standard <> operator allows passing strange things like date| to run processes rather than read files.

For safer filename-only operation while supporting older versions of Perl, you could use ARGV::readonly or emulate the <<>> operator like the following:

#!/usr/bin/env perl
use strict;
use warnings;
unshift @ARGV, '-' unless @ARGV;
while (my $file = shift) {
  my $fh;
  if ($file eq '-') {
    $fh = \*STDIN;
  } else {
    open $fh, '<', $file or die "open $file failed: $!";
  }
  while (my $line = <$fh>) {
    # ...
  }
}

(Technically the <<>> operator also does not allow passing - as an argument to read STDIN, but it is your choice if you want to allow that.)

It appears that the following script fills the bill.

#!/usr/bin/perl
use strict;
use warnings;
use 5.18.2;
local $/ = ""; # input record separator: one paragraph at a time
while (<>) {
    print;
    print "\n";
    say '-' x 30;
}

Example:

printf '%b' 'dog \ncat \nrat\n' > aaa
try.pl aaa
cat aaa | try.pl
try.pl < aaa

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM