Wie kann man stdout beim Piping von Befehlen in cmd.exe unter Windows entbinden?

1444
szr

Gegeben das Folgende:

C:\>perl -E " say STDOUT 111; say STDERR 222; say STDOUT 333; " 111 222 333  C:\>perl -E " say STDOUT 111; say STDERR 222; say STDOUT 333; " | cat 222 111 333 

Die Reihenfolge der Ausgabe bleibt beim Piping-Befehl nicht erhalten, da stdout gepuffert und stderr nicht gepuffert wird. Wie kann stdout zuverlässig ungepuffert werden, damit die Reihenfolge beim Piping von Befehlen erhalten bleibt?

Ich habe alles gesucht, um Lösungen zu finden, ich habe Skripte wie unbufferaus dem expectPaket in Cygwin und Linux ausprobiert, aber das funktioniert nur innerhalb von Cygwin (außerhalb davon in nacktem cmd.exe land, die Reihenfolge ist immer noch falsch, stderr.) kommt noch früher als erwartet.) Gleiches mitstdbuf -i0 -o0 -e0 ...

Jede Hilfe wäre sehr dankbar.

2
Das Problem ist nicht wirklich eine Pufferung, sondern eine Umleitung: Die "stdout" -Texte werden verzögert, indem sie an "cat" geleitet werden, während diejenigen an "stderr" beim Erstellen direkt in das Terminal geschrieben werden. Die einfachste Lösung wäre, "stderr" vor dem Piping in "stdout" umzuleiten, wie in "... 2> & 1 |" Katze`. Es gibt keine Möglichkeit sicherzustellen, dass das Ausführen von "cat" die Ausführung von "perl" unterbricht. AFH vor 8 Jahren 0
@AFH Danke, aber ich habe das auch schon ausprobiert, landet aber immer noch nicht in der Reihenfolge: `C: \> perl -E" sagt STDOUT 111; sagt STDERR 222; sagt STDOUT 333; "2> & 1 | cat` => `222 111 333` szr vor 8 Jahren 0
Das hätte ich nicht erwartet: Ohne `perl` unter Windows ist es nicht so einfach zu testen. Ich vermute, es liegt daran, dass beide Ausgabeströme gepuffert sind und die Ausgabe nur generiert wird, wenn beide geschlossen werden. In diesem Fall hängt die Reihenfolge von der Reihenfolge des Schließens der Dateien ab. In einem C-Programm können Sie festlegen, dass die Ausgabeströme nicht gepuffert werden, oder nach jedem 'fputs'-Programm' fflush 'programmieren, aber ich weiß nicht, ob dies in `perl` möglich ist - rufen Sie dazu vielleicht eine C-Funktion auf? AFH vor 8 Jahren 0

1 Antwort auf die Frage

0
ShadowRanger

Der standardmäßige E / A-Layer-Puffer von Perl wird normalerweise nicht verwendet stdio, weshalb unbufferund stdbuf(welche die Standardpufferung modifizieren stdio) nicht funktionieren.

Perl bietet jedoch eine eigene Methode zur Steuerung der verwendeten E / A-Schichten: Die PERLIOUmgebungsvariable. Gemäß den man perlrunDokumenten sollte es möglich sein, set PERLIO=:unixvor dem Ausführen des Befehls ausgeführt zu werden, oder für rohe, native Windows-Handle-basierte E / A-Operationen, die möglicherweise noch experimentell oder fehlerhaft sind set PERLIO=:win32. Entweder sollte man das normale Pufferungsverhalten umgehen, indem man direkt zu den rohen Systemaufrufen geht.

Angenommen, sich catselbst ist ungepuffert (ich glaube, dass es rohe Lese- und Schreibvorgänge ohne Pufferung verwendet, so sollte es sein), dies garantiert jedoch nicht das gewünschte Verhalten. Perl könnte die Daten catsofort senden, aber wenn cates nicht gelingt, sie schneller einzulesen und zurückzuschreiben, als Perl in die nächste Zeile wechseln und drucken kann, STDERRwird die STDERRAusgabe immer noch angezeigt. In lokalen Tests (unter Linux, aber es sollte ziemlich ähnlich sein) mit PERLIO=:unix, Pipe to cat, habe ich folgende Ausgaben gesehen:

222111  333 

dann:

222 111 333 

dann:

111222  333 

dann (zweimal hintereinander):

111 222 333 

Der Punkt ist, dass selbst bei Pufferung außerhalb der Gleichung die Rohrleitung Rennbedingungen aufgrund der Parallelität auf Prozessebene einführt. Der einzige Weg, dies zu umgehen, ist sicherzustellen, dass beide Streams zu cat:

perl -E "say STDOUT 111; say STDERR 222; say STDOUT 333;" 2>&1 | cat 

konsistent liefert:

111 222 333 

weil alle Daten catunmittelbar vor der nächsten printAusführung an gesendet werden . Der einzige Weg, um (meistens) zuverlässig zu bestellen, besteht darin, zwischen den Ausdrucken zu schlafen (wodurch catdas Rennen mit gewonnen werden kann perl).