简体   繁体   English

可以编写一个Perl脚本来从(1)文件,(2)stdin,(3)重定向中的任何一个接收数据吗?

[英]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; 几种unix实用程序,例如fmt,head和cat,可以通过以下三种方式中的任何一种来接收数据: 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? 可以编写一种功能相同的perl脚本吗? 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? “标准输入的管道”是引用以cat开头的代码行的正确方法吗?

I want to write myfmt.pl, to be used in any of these three ways. 我想编写myfmt.pl,以这三种方式中的任何一种使用。

The ARGV special filehandle will do this by default. 默认情况下, ARGV特殊文件句柄将执行此操作。 It is also the handle used by readline (aka the <> and <<>> operators) when not given a handle. 当没有给定句柄时,它也是readline(也称为<><<>>运算符)使用的句柄。 So this is actually pretty common in Perl scripts. 因此,这实际上在Perl脚本中很常见。

#!/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| 您可以使用<>运算符来支持较早版本的Perl,但是如果可用, Perl 5.22中添加<<>>运算符是更好的选择,因为标准的<>运算符允许传递诸如date|类的奇怪内容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: 为了在支持较旧版本的Perl时更安全的仅文件名操作,可以使用ARGV :: readonly或模拟<<>>运算符,如下所示:

#!/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.) (从技术上讲, <<>>运算符也不允许传递-作为读取STDIN的参数,但是如果要允许它,则由您选择。)

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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