Можно ли написать Perl-скрипт для получения данных из любого из (1) файла, (2) стандартного ввода, (3) перенаправления? - PullRequest
1 голос
/ 27 марта 2019

Несколько утилит unix, таких как fmt, head и cat, могут получать данные любым из трех способов: имя файла; труба со стандартного ввода; или перенаправление "<". Например: </p>

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

Можно ли написать Perl-скрипт, который будет вести себя с той же универсальностью? Или есть веская причина не пытаться это делать? И является ли «труба из стандартного ввода» правильным способом ссылки на строку кода, которая начинается с cat?

Я хочу написать myfmt.pl, который будет использоваться любым из этих трех способов.

Ответы [ 2 ]

5 голосов
/ 27 марта 2019

Специальный файловый дескриптор ARGV сделает это по умолчанию. Это также дескриптор, используемый readline (он же операторы <> и <<>>), когда ему не дан дескриптор. Так что это довольно часто встречается в скриптах 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
}

Вместо этого вы можете использовать оператор <> для поддержки более старых версий Perl, но оператор <<>> , добавленный в Perl 5.22 , является лучшим вариантом для этой задачи, если он доступен, поскольку стандартный <> оператор позволяет передавать странные вещи, такие как date|, чтобы запускать процессы, а не читать файлы.

Для более безопасной работы только с именами файлов при поддержке более старых версий 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>) {
    # ...
  }
}

(Технически, оператор <<>> также не разрешает передавать - в качестве аргумента для чтения STDIN, но это ваш выбор, если вы хотите это разрешить.)

1 голос
/ 27 марта 2019

Похоже, что следующий скрипт заполняет счет.

#!/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;
}

Пример:

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