Schrift
[thread]8092[/thread]

Pipes: kleines Verständnis Problem

Leser: 2


<< >> 5 Einträge, 1 Seite
sid burn
 2006-06-19 23:40
#67452 #67452
User since
2006-03-29
1520 Artikel
BenutzerIn

user image
Hi zusammen,
ich habe zur Zeit ein kleines Verständnis Problem mit Pipes. Den größten Teil des Problems habe ich mit Testen gelößt, mir sind aber bestimmte Sachen noch nicht ganz klar, und hoffe ihr könnt mir dabei Helfen.

Ich selber wollte ersteinmal Testweise wissen wie ich einen Parallelen Prozess starten kann, und diesen laufen lassen kann, und dabei trotzdem noch das Perl Programm weiter läuft.

2 Möglichkeiten gab es da also. (Bestimmt gibt es noch mehrere...)

Code: (dl )
1
2
open PIPE, "| grep -i welt";
open PIPE, "cat datei |";


Die erste Lösung soll also bedeuten das alles was ich an <PIPE> sende sozusagen nach grep gepiped wird. Auf der Shell also identisch mit:

Code: (dl )
$ Mein_Programm | grep -i welt


Die Zweite Lösung wird zum Lesen benutzt. Als Shellkommando also identisch mit:

Code: (dl )
$ cat datei | Mein_Programm



Ich hatte also zum testen mal "tethereal" aufgerufen, und wollte den Inhalt einfach nur wieder ausgeben, um auch zu schauen ob das mit dem Parallelen Prozess klappt. Das dies kein Sinn hat ist mir schon klar, ich wollte das nur als Test benutzen.

Ich schrieb also folgendes:

Code: (dl )
1
2
3
open ETH, "tethereal |";
print <ETH>;
close ETH;


Naja und zu meinen Verblüffen muss ich sagen, dass dies erstmal nicht klappte, anders als erwartet. Ich habe das auch mal mit "find" ausprobiert, und es scheint so das er erst das Programm ausführt, und erst wenn alles fertig ist, eine Ausgabe erscheint. Die Verwendung war also irgendwie identisch als hätte ich backticks verwendet. Bei einem Prozess wie tethereal der in Echtzeit Informationen ausgibt, und solange läuft wie man es abbricht, ist das ganze sicherlich unbrauchbar.

Zum Testen habe ich also mal das Pipe zeichen nach vorne gestellt, und auf einmal ging es wie erwartet:

Code: (dl )
1
2
3
open ETH, "| tethereal";
print <ETH>;
close ETH;


Dies gibt mir sofort alles aus was tethereal ausgibt. Mein Problem erstmal hierdran. Ich verstehe die Zuordnung nicht mehr. Eigentlich benutzt man diese Schreibweise doch zum Schreiben, und nicht zum Lesen? Und warum erscheint hierbei sofort eine Ausgabe, und beim eigentlichen richtigen Pipe hinten anhängen nicht?


Okay, habe dann nochmal schnell etwas nachgelesen, und habe folgende Lösung gefunden.

Code: (dl )
1
2
3
open ETH, "tethereal |";
print while <ETH>;
close ETH;


Das ganze Funktioniert jetzt genauso wie die Lösung davor. Allerdings verstehe ich nicht ganz warum ich das ganze unbedingt in einer while Schleife erledigen muss, und warum ein print nicht Funktioniert?

Mir ist klar das print im Listenkontext Arbeitet. Passiert also folgendes das die komplette Ausgabe erst komplett eingelesen wird, und dann erst ausgegeben wird?

Da das while Konstrukt ja im Skalaren Kontext Arbeitet liest es nur bis zum nächsten Newline, und gibt den Inhalt aus? Jedenfalls wäre das meine Persönliche Erklärung. Allerdings verstehe ich nicht ganz warum ich hier unbedingt den Skalaren Kontext benutzen muss, und es mit vorangestellten Pipe Zeichen auch im Listenkontext von print arbeitet. Vor allem verstehe ich nicht wie das mit dem vorangestellten Pipe überhaupt Funktionieren soll.


Beim Schreiben bin ich noch auf die Idee gekommen das es vielleicht am Output Buffer liegen könnte warum es mit dem nachgestellten Pipe und dem print nicht klappt. Ich habe also "$| = 1" am Anfang gesetzt. Verändert hat sich allerdings trotzdem nichts, und es gibt die Meldungen immer noch nciht direkt auf dem Bildschirm aus.


Von daher meine Frage was passiert genau beim Ausgeben mit print. Und wie/warum funktioniert das ganze mit dem vorangestellten Pipe?



Eine ganz andere Frage, ich benutze open lieber mit 3 Argumente. Wie kann ich bei 3 Arguementen Angeben das das Pipe vorne bzw. hinten steht?\n\n

<!--EDIT|sid burn|1150746216-->
Nicht mehr aktiv. Bei Kontakt: ICQ: 404181669 E-Mail: perl@david-raab.de
pq
 2006-06-20 00:00
#67453 #67453
User since
2003-08-04
12208 Artikel
Admin1
[Homepage]
user image
das print <PIPE> liest tatsächlich erst alles ein und gibt es dann aus.

mit der 3-argumenten-form von open könnte sowas so aussehen:
Code: (dl )
1
2
3
open my $pipe, "|-", "programm" or die $!;
print while <$pipe>;
close $pipe;
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. -- Damian Conway in "Perl Best Practices"
lesen: Wiki:Wie frage ich & perlintro Wiki:brian's Leitfaden für jedes Perl-Problem
sid burn
 2006-06-20 00:46
#67454 #67454
User since
2006-03-29
1520 Artikel
BenutzerIn

user image
Quote
das print <PIPE> liest tatsächlich erst alles ein und gibt es dann aus.

Erstmal Danke für die Antwort.

Ich habe noch etwas weiter getestet und ich glaube ich bin auf die Lösung des Problems gekommen. (Beziehungsweise war es eher ein Denkfehler von mir) Noch immer gibt es ja einen unterschied zwischen:

Code: (dl )
1
2
open PIPE, "-|", "grep -r hostname /etc";
print <PIPE>;

Das liest erst alles ein, und gibt dann alles aus.

Code: (dl )
1
2
3
open PIPE, "|-", "grep -r hostname /etc";
print <PIPE>;
close PIPE;

Gibt sofort alles aus, durch deine Antwort habe ich nochmal etwas weiter getestet.

Code: (dl )
1
2
3
4
open GREP, "|-", "grep -r hostname /etc";
@data = <GREP>;
print scalar @data;
close GREP;


Dieses Stückchen Code gibt trotzdem das ergebnis des greps zurück, obwohl ich das nirgendswo anfordere. Anscheind ist es so, dass wenn ich jedesmal "<GREP>" aufrufe mein Kommando aufgerufen wird. Da ich aber nichts an <GREP> übergebe wird der Befehl ganz normal verarbeitet. Und Lesend davon zugreifen geht auch nicht. Da ich also nichts auslese ist es praktisch das selbe als würde ich den Befehl einmal ausführen, und danach wieder zurück zu meinen Perl Programm kommen, es ist also logisch warum ich die Ausgabe sofort sehe, vom verhalten her ist es praktisch das selbe als hätte ich system() benutzt.

Der Beweis das ich ja nichts auslese ist, dass @data Leer bleibt.

Eigentlich ist das ganze identisch mit diesem Code:
Code: (dl )
echo "" | grep -r hostname /etc


Irgendwie wird mir das ganze Konstrukt jetzt einleuchtend :blush: Und Sinn ergibt es nicht wirklich das Pipe vorne an zu schreiben, und es ist wohl auch nicht das was jemand möchte. (Jedenfalls in diesem Fall) ^^
Nicht mehr aktiv. Bei Kontakt: ICQ: 404181669 E-Mail: perl@david-raab.de
Dubu
 2006-06-20 02:30
#67455 #67455
User since
2003-08-04
2145 Artikel
ModeratorIn + EditorIn

user image
Sehr schön beschrieben.
docsnyder
 2006-06-20 10:52
#67456 #67456
User since
2005-09-08
300 Artikel
BenutzerIn
[Homepage] [default_avatar]
@sid burn

Wenn Du eine Pipe zum Schreiben öffnest, "grep -r hostname /etc" aber nicht von STDIN liest (Du hast ja Parameter angegeben!), dann läuft grep in der Tat ab, wie wenn Du system() aufrufst. Die Ausgabe, die Du bekommst, ist von grep (auf STDOUT) und hat nichts mit Deiner Pipe zu tun (denn die liest allenfalls von STDIN, was grep in diesem Fall aber nicht tut).

Gruß, Doc
<< >> 5 Einträge, 1 Seite



View all threads created 2006-06-19 23:40.