Programmgesteuert aus STDIN oder Eingabedatei in Perl lesen

74

Was ist der einfachste Weg, um programmgesteuert aus stdin oder einer Eingabedatei (falls vorhanden) in Perl zu lesen?

Syker
quelle

Antworten:

87
while (<>) {
print;
}

liest entweder aus einer in der Befehlszeile angegebenen Datei oder aus stdin, wenn keine Datei angegeben ist

Wenn Sie diese Schleifenkonstruktion in der Befehlszeile benötigen, können Sie die folgende -nOption verwenden:

$ perl -ne 'print;'

Hier setzen Sie einfach Code zwischen {}dem ersten Beispiel und dem ''zweiten

ennuikiller
quelle
23
+1 + nitpick: "liest aus einer oder mehreren Dateien, die nacheinander in der Befehlszeile angegeben wurden"
msw
4
... und alles, was Sie tun müssen, ist zu schreiben @ARGV = "/path/to/some/file.ext";und die Datei zu lesen - so können Sie unter bestimmten Bedingungen sogar eine Standarddatei programmieren.
Axeman
3
Und wenn Ihr Skript sehr kurz ist, können Sie die Optionen -n oder -p verwenden, um zu perlen, und Ihre Verarbeitung in der Befehlszeile angeben : perl -n -e '$_ = uc($_); print;' yourfile. Mit -p anstelle von -n druckt Perl am Ende automatisch $ _.
Mivk
3
Und natürlich können Sie alles auf einmal "schlürfen":my @slurp = <>; foreach my $line (@slurp) { ... }
David Tonhofer
Gibt es einen Grund, warum Sie die gelesene Zeile nicht mit so etwas benennen while (my $line = <>) {...?
David Mertens
47

Dies bietet eine benannte Variable, mit der gearbeitet werden kann:

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

Um eine Datei zu lesen, leiten Sie sie wie folgt ein:

program.pl < inputfile
Ron
quelle
10
+1 für die Vermeidung des allzu häufigen unlesbaren Perl-Codes
MikeKulls
6
-1, da foreach die gesamte Datei schlürft. Besser der Zeile in einer while-Schleife zuweisen. Darüber hinaus verfügt Perl über ein integriertes magisches Verhalten für spitze spitze Klammern. Dann ist keine Umleitung erforderlich.
David Mertens
3
Die erste Zeile sollte lauten: foreach my $line ( <STDIN> ) { Ich stimme @MikeKulls zu. Es ist nicht Perls Schuld, wenn Perl-Skripte nicht lesbar sind. Hier sind Programmierer schuld!
Tiktak
1
Beim erneuten Lesen der Frage ist diese Antwort falsch, da sie nur von stdin liest und keine in der Befehlszeile angegebene Datei liest. Die Antwort von ennuikiller ist richtig, obwohl ich sie als schreiben würde while(my $line = <>) { print $line; }.
MikeKulls
2
@MikeKulls Sollte das nicht sein while (my $line = <>, defined $line) { ... }oder while (<>) { my $line = $_; }um nicht in einer leeren Zeile stehen zu bleiben ?
Gregory Nisbet
15

In bestimmten Situationen ist es am "schicksten", den -nSchalter zu nutzen . Es umschließt Ihren Code implizit mit einer while(<>)Schleife und verarbeitet die Eingabe flexibel.

In slickestWay.pl:

#! / usr / bin / perl -n

START: {
  # hier mal was machen
}}

# Logik für eine einzelne Eingabezeile implementieren
print $ result;

In der Kommandozeile:

chmod +x slickestWay.pl

Führen Sie nun abhängig von Ihrer Eingabe einen der folgenden Schritte aus:

  1. Warten Sie auf Benutzereingaben

    ./slickestWay.pl
    
  2. Lesen Sie aus den in den Argumenten genannten Dateien (keine Umleitung erforderlich).

    ./slickestWay.pl input.txt
    ./slickestWay.pl input.txt moreInput.txt
    
  3. Verwenden Sie ein Rohr

    someOtherScript | ./slickestWay.pl 
    

Der BEGINBlock ist erforderlich, wenn Sie eine objektorientierte Schnittstelle wie Text :: CSV oder eine andere initialisieren müssen, mit der Sie dem Shebang hinzufügen können -M.

-lund -psind auch deine Freunde.

Neil Best
quelle
13

Sie müssen den Operator <> verwenden:

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

Welches kann verdichtet werden, um:

print while (<>);

Beliebige Datei:

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

Wenn es einen Grund gibt, warum Sie die von ennuikiller oben bereitgestellte einfache Lösung nicht verwenden können , müssen Sie Typeglobs verwenden, um Dateihandles zu bearbeiten. Das ist viel mehr Arbeit. Dieses Beispiel kopiert von der Datei in $ARGV[0]die in $ARGV[1]. Der Standardwert ist STDINund STDOUTjeweils , wenn die Dateien nicht angegeben werden.

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($_);
}
Sigusr2
quelle
+1 für eine Methode, die funktioniert, wenn der zu lesende Dateiname nicht in der Befehlszeile angegeben wird, sondern an einer anderen Stelle (in einer Variablen aus der Konfigurationsdatei usw. - Sie ersetzen einfach $ARGV[0]usw. durch eine andere Variable), wo alle anderen Antworten fehlschlagen ...
Matija Nalis
Oder zum Lesen einfach unshiftden Dateinamen auf @ARGVund verwenden Sie den Diamantoperator <>.
David Mertens
7

Machen

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

wenn Sie nur eine Zeile lesen möchten

Thorsten Niehues
quelle
Liest nur aus STDIN, nicht aus der angegebenen Datei. Der Diamantoperator ist genau das , wonach das OP sucht.
David Mertens
0

Hier ist, wie ich ein Skript erstellt habe, das entweder Befehlszeileneingaben annehmen oder eine Textdatei umleiten lassen kann.

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


Dadurch wird der Inhalt der Datei @ARGV neu zugewiesen. Von dort aus verarbeiten Sie @ARGV einfach so, als würde jemand Befehlszeilenoptionen einschließen.

WARNUNG

Wenn keine Datei umgeleitet wird, bleibt das Programm im Leerlauf, da es auf die Eingabe von STDIN wartet.

Ich habe noch keine Möglichkeit gefunden, festzustellen, ob eine Datei umgeleitet wird, um das STDIN-Problem zu beheben.

Westrock
quelle
Dies ist ein cooler Ansatz, aber nicht das, wonach das OP gefragt hat. Dies ermöglicht die Übergabe eines einzelnen Dateinamens als Argument, dessen Inhalt als Befehlszeilenargumente verwendet wird. OP suchte nach etwas anderem. Auch warum ist das Kryptische $#ARGV < 1statt (was ich als) klarer @ARGV == 1?
David Mertens
-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(<>);
}
trapd00r
quelle
7
Der einfache <>Operator findet und liest automatisch alle in der Befehlszeile angegebenen Dateien. Es gibt keine Notwendigkeit für die if.
Dave Sherohman
Sie beschreiben auch nicht, was shifthier tut
Eugen Konkov