2012-08-30 18 views
6

Ich lese ein paar Zeilen von STDIN. Wie kann ich den Rest von STDIN an einen Befehl übergeben, der von der Standardeingabe liest (z. B. md5sum oder wc)?Perl: übergeben Sie Dateigriff an ein Programm lesen STDIN

Ich konnte ein tun:

read_a_few_lines_from_diamond_operator(); 
open (C, "|cmd"); 
while(<>) { print C } 
close C; 
cleanup_after_C(); 

aber für efficency Gründen würde Ich mag nicht den Eingang berühren, sondern die Dateikennung von STDIN übergeben. Art wie:

seq 10 | (read A; wc) 

wo read so viel liest, wie es die Ruhe vor Weitergabe an wc mag. Ich kann diese Lösung jedoch nicht verwenden, da ich den Befehl aus meinem Perl-Programm heraus starten muss und ich nach Abschluss der cmd Arbeit arbeiten muss.


Ich lese ein paar Zeilen aus der Datei 'foo'. Wie kann ich den Rest an einen Befehl übergeben, der von der Standardeingabe liest (z. B. md5sum oder wc)?

Ich konnte ein tun:

open (F, "<foo"); 
read_a_few_lines_from_F(); 
open (C, "|cmd"); 
while(<F>) { print C } 
close C; 
cleanup_after_C(); 

aber für efficency Gründen würde Ich mag nicht den Eingang berühren, sondern den Rest der Datei ‚foo‘ übergeben.


Ich habe das Gefühl, es kann Tricks zu tun mit wie select, open(FOO,">&STDOUT), exec 6<&0, fork, pipe.

Antwort

8

Die Antwort ist ganz einfach: Sie müssen nichts Besonderes tun. Ihr Kind erbt automatisch STDIN mit system und exec. Alles, was Sie nicht von STDIN gelesen haben, wird für das Kind lesbar sein.

Es gibt jedoch ein Problem. Da das Lesen eines Zeichens auf einmal ineffizient ist, liest Perl Block für Block aus der Datei. Das heißt, Sie lesen mehr aus der Datei als die "paar Zeilen", die Sie von Perl erhalten haben. Dies ist deutlich zu erkennen Sie den folgenden Befehl:

perl -E'say $_ x 500 for "a".."z"' \ 
    | perl -e'<>; <>; exec("cat");' \ 
    | less 

Statt zu Beginn der zweiten Zeile des Startens cat beginnt in der Mitte des „q“ s (bei Byte 8192)!

Sie müssten von Lesezeilen mit readline (<>) zum Lesen einzelner Bytes mit sysread wechseln, wenn Sie möchten, dass dies funktioniert.


auf das größere Bild Focusing, ich denke, es gibt eine Lösung:

open(STDIN, "<", "foo") or die $!; 
read_a_few_lines(*STDIN); 
my $pos = tell(STDIN); 
open(STDIN, "<", "foo") or die $!; 
sysseek(STDIN, $pos, SEEK_SET); 
system(@cmd); 
... 

Oder vielleicht sogar:

open(STDIN, "<", "foo") or die $!; 
read_a_few_lines(*STDIN); 
sysseek(STDIN, tell(STDIN), SEEK_SET); 
system(@cmd); 
... 

Ungeprüfte.

+0

Elegante Lösung, die Ihnen einen Daumen hoch holt, aber es hat 2 Probleme: Es tötet Perl ab (ich habe die Frage geklärt, um klar zu machen, dass das für mich nicht funktionieren wird); und es behandelt nicht den 2. Teil (Lesen der Datei 'foo'). –

+0

Warum funktioniert es nicht? Wie die Antwort sagt, funktioniert es sowohl für 'system' als auch' exec'. Ist 'Perl -e 'druckt <>; System ("Katze"); print "still here \ n" ' tripleee

+0

Gut entdeckt. Das funktioniert: 'seq 10 | perl -e 'sysread (STDIN, $ a, 1); Druck "$ a bar"; System ("Katze"); drucke "still here \ n" ''. Es bleibt jedoch immer noch die Datei 'foo' zu lesen. –