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


75

Який найгарячіший спосіб програмно читати з stdin або вхідного файлу (якщо передбачено) у Perl?

Відповіді:


88
while (<>) {
print;
}

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

Якщо вам потрібна ця побудова циклу в командному рядку, тоді ви можете використовувати -nопцію:

$ perl -ne 'print;'

Тут ви просто поміщаєте код між {}першим прикладом і ''другим


23
+1 + nitpick: "буде читати з одного або декількох файлів, послідовно вказаних у командному рядку"
msw

4
... і все, що вам потрібно зробити, це написати @ARGV = "/path/to/some/file.ext";і він зчитує файл - так що ви навіть можете запрограмувати файл за замовчуванням за певних умов.
Axeman

3
І якщо ваш сценарій дуже короткий, ви можете використовувати -n або -p опції для Perl, і вказати обробку в командному рядку: perl -n -e '$_ = uc($_); print;' yourfile. За допомогою -p замість -n, perl автоматично друкує $ _ в кінці.
mivk

3
І звичайно, ви можете "поцупити" все одним my @slurp = <>; foreach my $line (@slurp) { ... }
рухом

Чи є причина, чому ви не називаєте прочитаний рядок чимось на зразок while (my $line = <>) {...?
Девід Мертенс,

48

Це забезпечує іменовану змінну для роботи:

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

Щоб прочитати файл, вставте його так:

program.pl < inputfile

10
+1 за уникнення занадто поширеного скорочення нечитабельного коду Perl
MikeKulls

6
-1, оскільки foreach викличе весь файл. Краще призначити рядку через цикл while. Крім того, Perl має вбудовану магічну поведінку для оголених кутових дужок, тому вам слід було сказати while (моя $ рядок = <>). Тоді переспрямування не потрібно.
Девід Мертенс

3
Перший рядок повинен бути таким, що foreach my $line ( <STDIN> ) { я погоджуюсь з @MikeKulls. Це не вина Perl, якщо сценарії Perl є нечитабельними. Тут винні програмісти!
tiktak

1
Перечитуючи запитання, ця відповідь неправильна, оскільки вона читає лише з stdin, а не читає файл, зазначений у командному рядку. Відповідь ennuikiller правильна, хоча я б це написав як while(my $line = <>) { print $line; }.
MikeKulls

2
@MikeKulls Хіба це не повинно бути while (my $line = <>, defined $line) { ... }або while (<>) { my $line = $_; }щоб уникнути зупинки на порожньому рядку?
Грегорі Нісбет

15

Найбільш «найсмачніший» спосіб у певних ситуаціях - скористатися -nперемикачем . Він неявно обгортає ваш код while(<>)циклом і гнучко обробляє введення.

В slickestWay.pl:

#! / usr / bin / perl -n

ПОЧАТИ: {
  # зробіть щось тут один раз
}

# реалізувати логіку для одного рядка вводу
надрукувати результат $;

У командному рядку:

chmod +x slickestWay.pl

Тепер, залежно від вашого вводу, зробіть одне з наступного:

  1. Зачекайте введення користувачем

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

    ./slickestWay.pl input.txt
    ./slickestWay.pl input.txt moreInput.txt
    
  3. Використовуйте трубу

    someOtherScript | ./slickestWay.pl 
    

BEGINБлок необхідний , якщо вам потрібно форматувати яке - то об'єктно-орієнтований інтерфейс, такі як Text :: CSV або деякі такі, які ви можете додати в кубло з -M.

-lа -pтакож ваші друзі.


13

Вам потрібно використовувати оператор <>:

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

Що можна ущільнити:

print while (<>);

Довільний файл:

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

9

Якщо є причина, по якій ви не можете використовувати просте рішення, надане 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($_);
}

+1 для способу, який буде працювати, якщо ім'я файлу для читання не вказане в командному рядку, а десь ще (у якійсь змінній читайте з конфігураційного файлу і т. Д. - ви просто замінюєте $ARGV[0]etc на іншу змінну), де всі інші відповіді не вдаються ...
Matija Nalis

Або, для читання, тільки unshiftім'я файлу на @ARGVі використовувати оператор алмазного <>.
Девід Мертенс,

7

Роби

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

якщо ви хочете прочитати лише один рядок


Зчитує лише зі STDIN, а не з вказаного файлу. Алмазний оператор - це саме те, що шукає ОП.
Девід Мертенс,

0

Ось як я створив скрипт, який може приймати або введення з командного рядка, або перенаправляти текстовий файл.

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


Це перепризначить вміст файлу @ARGV, звідти ви просто обробляєте @ARGV так, ніби хтось включав параметри командного рядка.

ПОПЕРЕДЖЕННЯ

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

Я ще не знайшов способу виявити, чи перенаправляється файл, щоб усунути проблему STDIN.


Це крутий підхід, але не той, про який просив ОП. Це дає можливість передавати одне ім'я файлу як аргумент, вміст якого використовується як аргументи командного рядка. OP шукав щось інше. Крім того, чому загадкове $#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
Звичайний <>оператор автоматично знайде і прочитає будь-які файли, наведені в командному рядку. У цьому немає необхідності if.
Dave Sherohman

Ви також не описуєте, що shiftтут робите
Євген Конков
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.