Программно читать из STDIN или входного файла в Perl

60

Каков slickest способ программно читать из stdin или входного файла (если предоставлено) в Perl?

Теги:
stdin

9 ответов

75
Лучший ответ
while (<>) {
print;
}

будет читаться либо из файла, указанного в командной строке, либо из stdin, если файл не указан

Если вам нужна эта конструкция цикла в командной строке, вы можете использовать опцию -n:

$ perl -ne 'print;'

Здесь вы просто помещаете код между {} из первого примера в '' во второй

  • 21
    +1 + nitpick: «будет читать из одного или нескольких файлов, последовательно указанных в командной строке»
  • 4
    ... и все, что вам нужно сделать, это написать @ARGV = "/path/to/some/file.ext"; и он читает файл - так что вы даже можете запрограммировать файл по умолчанию при определенных условиях.
Показать ещё 3 комментария
40

Это обеспечивает именованную переменную для работы с:

foreach my $line ( <STDIN> ) {
    chomp( $line );
    print "$line\n";
}

Чтобы прочитать файл, проведите его так:

program.pl < inputfile
  • 9
    +1 за то, что избегаете слишком распространенного нечитаемого Perl-кода.
  • 3
    -1, так как foreach будет хлебать весь файл. Лучше назначить линию в цикле while. Кроме того, в Perl есть магическое поведение для простых угловых скобок, поэтому вы должны были сказать while (my $ line = <>). Тогда перенаправление не требуется.
Показать ещё 5 комментариев
12

Вам нужно использовать < > operator:

while (<>) {
    print $_; # or simply "print;"
}

который может быть спрессован до:

print while (<>);

Произвольный файл:

open F, "<file.txt" or die $!;
while (<F>) {
    print $_;
}
close F;
11

В некоторых ситуациях "скользкий" способ заключается в использовании переключателя -n. Он неявно обертывает ваш код циклом while(<>) и гибко управляет входным сигналом.

В slickestWay.pl:

#!/usr/bin/perl -n

BEGIN: {
  # do something once here
}

# implement logic for a single line of input
print $result;

В командной строке:

chmod +x slickestWay.pl

Теперь, в зависимости от вашего ввода, выполните одно из следующих действий:

  • Дождитесь ввода пользователем

    ./slickestWay.pl
    
  • Чтение из файлов, названных в аргументах (не требуется перенаправление)

    ./slickestWay.pl input.txt
    ./slickestWay.pl input.txt moreInput.txt
    
  • Используйте трубку

    someOtherScript | ./slickestWay.pl 
    

Блок BEGIN необходим, если вам нужно инициализировать какой-то объектно-ориентированный интерфейс, такой как Text:: CSV или некоторые такие, которые вы можете добавить к shebang с помощью -M.

-l и -p также являются вашими друзьями.

7

Если есть причина, вы не можете использовать простое решение, предоставленное ennuikiller выше, тогда вам придется использовать Typeglobs для управления файловыми дескрипторами. Это больше работает. В этом примере копируется из файла в $ARGV[0] в файл $ARGV[1]. По умолчанию это значения STDIN и STDOUT, если файлы не указаны.

use English;

my $in;
my $out;

if ($#ARGV >= 0){
    unless (open($in,  "<", $ARGV[0])){
      die "could not open $ARGV[0] for reading.";
    }
}
else {
    $in  = *STDIN;
}

if ($#ARGV >= 1){
    unless (open($out, ">", $ARGV[1])){
      die "could not open $ARGV[1] for writing.";
    }
}
else {
    $out  = *STDOUT;
}

while ($_ = <$in>){
    $out->print($_);
}
  • 0
    +1 для способа, который будет работать, если имя файла для чтения не указано в командной строке, но где-то еще (в некоторой переменной, чтение из файла конфигурации и т. Д. - вы просто заменяете $ARGV[0] т. Д. На другую переменную), где все остальные ответы потерпеть поражение...
  • 0
    Или для чтения просто unshift имя файла на @ARGV и используйте оператор diamond <> .
6

Do

$userinput =  <STDIN>; #read stdin and put it in $userinput
chomp ($userinput);    #cut the return / line feed character

если вы хотите прочитать только одну строку

  • 0
    Читает только из STDIN, а не из указанного файла. Оператор с бриллиантами - это именно то, что ищет OP.
0

Бесстыдно украден из Neil Best и Рон

Предположим, что script name: stdinProcessor.pl

#!/usr/bin/perl

BEGIN: {
    print "Doing some stuff first\n";
}

foreach $line ( <STDIN> ) {
    chomp($line);
    print "$line\n";
}

# Do something at the exit
print "Iteration done\n"

Пример:

$echo '1\n2\n3' | ./stdinProcessor.pl
Doing some stuff first
1
2
3
Iteration done
0

Вот как я создал script, который может принимать либо входы командной строки, либо перенаправлять текстовый файл.

if ($#ARGV < 1) {
    @ARGV = ();
    @ARGV = <>;
    chomp(@ARGV);
}


Это переназначает содержимое файла на @ARGV, оттуда вы просто обрабатываете @ARGV, как если бы кто-то включал параметры командной строки.

ПРЕДУПРЕЖДЕНИЕ

Если файл не перенаправлен, программа будет сидеть в режиме ожидания, потому что ожидает ввода от STDIN.

Я не понял способ определить, перенаправляется ли файл, но для устранения проблемы с STDIN.

  • 0
    Это классный подход, но не тот, о котором просил ОП. Это позволяет передавать одно имя файла в качестве аргумента, содержимое которого используется в качестве аргументов командной строки. ОП искал что-то другое. Кроме того, почему загадочный $#ARGV < 1 вместо (о чем я думаю) более ясного @ARGV == 1 ?
-2
if(my $file = shift) { # if file is specified, read from that
  open(my $fh, '<', $file) or die($!);
  while(my $line = <$fh>) {
    print $line;
  }
}
else { # otherwise, read from STDIN
  print while(<>);
}
  • 7
    Оператор plain <> автоматически найдет и прочитает любой файл (ы), указанный в командной строке. Там нет необходимости, if .
  • 0
    Вы также не описываете, что здесь происходит shift

Ещё вопросы

Сообщество Overcoder
Наверх
Меню