Wie kann ich die Ausgabe in der Windows-Befehlszeile sowohl übermitteln als auch anzeigen?

5993
Bob

Ich habe einen Prozess, den ich in einer Batchdatei ausführen muss. Dieser Prozess erzeugt etwas Ausgabe. Ich muß sowohl diese Ausgabeanzeige auf den Bildschirm, und sende (Rohr), um es ein anderes Programm.

Die bash-Methode verwendet tee:

echo 'ee' | tee /dev/tty | foo 

Gibt es ein Äquivalent für Windows? Gerne verwende ich PowerShell bei Bedarf.

Es gibt teePorts für Windows, aber es scheint kein Äquivalent für zu sein /dev/tty, was die Sache kompliziert macht.


Der spezielle Anwendungsfall hier: Ich habe ein Programm (launch4j), das ich ausführen muss, um dem Benutzer die Ausgabe anzuzeigen. Gleichzeitig muss ich in der Lage sein, Erfolg oder Misserfolg im Skript zu erkennen. Leider setzt dieses Programm keinen Exit-Code, und ich kann ihn nicht dazu zwingen. Meine derzeitige Problemumgehung besteht darin find, die Ausgabe zu durchsuchen ( launch4j config.xml | find "Successfully created"), um die Ausgabe zu durchsuchen ( ) - dies schluckt jedoch die Ausgabe, die ich anzeigen muss. Daher brauche ich eine Möglichkeit, sowohl auf dem Bildschirm anzuzeigen als auch die Ausgabe an einen Befehl zu senden - und dieser Befehl sollte festlegen können ERRORLEVEL(er kann nicht asynchron ausgeführt werden). Dies wird in einem Build-Skript verwendet, das auf vielen verschiedenen Maschinen ausgeführt werden kann.

Für diesen speziellen Fall ist etwas Leichtes erforderlich - ich kann keine zusätzlichen Frameworks oder Interpreter installieren (z. B. Perl, wie in dieser Antwort vorgeschlagen ). Außerdem müssen kommerzielle Programme über eine Lizenz verfügen, die eine Weiterverteilung ermöglicht.

4
Wäre meine Antwort akzeptabler, wenn ich den Code kompiliert und einen Link zur ausführbaren Datei angegeben hätte? Ich kann das tun, wenn Sie möchten, wenn Sie keinen Zugriff auf einen Compiler haben oder dies nicht selbst tun möchten. BenjiWiebe vor 9 Jahren 0

6 Antworten auf die Frage

1
Bob

Ein etwas unordentlicher Weg, den ich mir vorstellen kann, ist, eines der portierten teeProgramme zu verwenden, in eine temporäre Datei zu speichern und dann die Datei mit zu testen find. Die Verwendung einer temporären Datei kann jedoch unerwünscht sein.

Wenn PowerShell eine Option ist, verfügt sie tatsächlich über ein Tee-OutputCmdlet. Es ist nicht ganz so direkt wie das Bash-Beispiel, aber es gibt eine -VariableOption zum Speichern der Ausgabe in einer Variablen, die dann durchsucht werden kann:

# save result in $LastOutput and also display it to the console echo "some text" | Tee-Output -Variable LastOutput  # search $LastOutput for a pattern, using Select-String # instead of find to keep it within PowerShell $Result = $LastOutput | Select-String -Quiet "text to find"  # $Result should contain either true or false now # this is the equivalent of batch "if errorlevel 1" if ($Result -eq $True) { # the string exists in the output } 

Um die allgemeinere Frage zu beantworten, ist es auch möglich, die Variable in ein beliebiges anderes Programm zu übergeben, das dann gesetzt wird $LastExitCode. Als Einzeiler, der von der grundlegenden Befehlszeile aus aufgerufen werden kann:powershell -c "echo text | Tee-Object -Variable Result; $Result | foo"

Ich bin immer noch auf der Suche nach einer Möglichkeit, dies ohne temporäre Datei in der grundlegenden Befehlszeile (nicht PowerShell) auszuführen, sofern dies möglich ist. Bob vor 9 Jahren 0
An * nix, ich "Tee" immer zu "stderr"; Gibt es eine Möglichkeit, in der PowerShell sowohl zu stderr als auch zu stdout zu "tippen", oder hat Windows / PowerShell dieses Konzept nicht? BenjiWiebe vor 9 Jahren 0
@BenjiWiebe `/ dev / stderr`, richtig? Das gibt es unter Windows nicht, soweit ich weiß. Etwas mit Named Pipes wäre möglich, aber ich versuche zu vermeiden, ein Programm nur für diesen Zweck zu schreiben! Bob vor 9 Jahren 0
Programmgesteuert ist "/ dev / stderr" ein Kernelkonzept, das Daten an den Dateideskriptor für "stderr" weiterleitet. Gibt es in Windows keine Möglichkeit, zu "stderr" umzuleiten (NICHT "/ dev / stderr")? BenjiWiebe vor 9 Jahren 1
Siehe meine Antwort für eine Erklärung dessen, was ich dachte (und es könnte funktionieren!) BenjiWiebe vor 9 Jahren 0
@BenjiWiebe Ah, ja, ich meine, es gibt kein direktes Äquivalent in Windows, das Dateideskriptoren als Gerätedateien verfügbar macht. Ja, ein Programm zu schreiben, das nur auf diese gedruckt wird, würde funktionieren. Bob vor 9 Jahren 0
Meinen Sie damit, dass mein Code ** tatsächlich funktionieren würde? !? :) BenjiWiebe vor 9 Jahren 0
@BenjiWiebe Ja, es sieht so aus, als sollte es funktionieren. Ich werde jetzt erst einmal mein PowerShell-Skript verwenden, da ich dadurch nicht mehr ein zusätzliches Binärprogramm hinzufügen muss, sondern eine positive Lösung für eine gute Lösung habe :) Bob vor 9 Jahren 0
In Powershell können Sie die Umleitung ausführen. Mit "*> & 1" werden alle Ausgaben auf "stdout" umgeleitet. Eris vor 9 Jahren 0
1
BenjiWiebe

Sie könnten diesen Code versuchen Übersetzung und Benutzung mag: echo something | mytee | foo.
Ich weiß nicht, ob es funktionieren wird, da ich nicht weiß, wie Windows mit beschäftigt stderr/ stdout, aber es könnte funktionieren.

#include <stdio.h> int main() { int c; while((c = fgetc(stdin)) != EOF) { printf("%c", c); fprintf(stderr, "%c", c); } return 0; } 
1
Shawn Melton

Warum führen Sie den Befehl nicht einfach in PowerShell aus Invoke-Commandund verwenden Sie die Ergebnisse in einer Variablen. Sie suchen die Variable nach Ihren Ergebnissen, wenn sie vorhanden sind, tun etwas und zeigen dann die gesamte Ausgabe auf der Konsole an.

Die Testdatei, von der die Ausgabe erfasst werden soll, ist nur ein Notizblock mit dem folgenden Text (C; \ Temp \ OutputTest.txt):

blahlbalsdfh abalkshdiohf32iosknfsda afjifwj93f2ji23fnsfaijfafds fwjifej9f023f90f3nisfadlfasd fwjf9e2902fjf3jifdsfajofsda jfioewjf0990f Successfully Created fsjfd9waf09jf329j0f3wjf90awfjw0afwua9 

In Ihrem Fall würden Sie Ihren Befehl jedoch als etwas bezeichnen, was {& "Launch4j" config.xml}ich glaube, aber für mein Beispiel:

Invoke-Command -ScriptBlock | foreach { $_; if ($_ -match "successfully created") {$flag = $true} } if ($flag) { "do whatever" } 
Genau das habe ich getan und in meiner Selbstantwort beschrieben ... Fügt diese Antwort weitere Informationen hinzu? Bob vor 9 Jahren 0
Ah, ich verstehe, der Prozess ist etwas anders (verwendet kein "Tee-Objekt", sondern druckt die Ausgabe später manuell). Ich nehme an, einer der Nachteile dieses Ansatzes besteht darin, dass er die gesamte Ausgabe erfasst und sie dann auf einmal anzeigt. Dies bedeutet, dass der Benutzer keine Ausgabe sieht, während der Prozess läuft, nur nachdem er beendet ist. Es ist akzeptabel für kurze Aufgaben, aber nicht gut für längere Aufgaben. Bob vor 9 Jahren 0
Bearbeitet, um einfach jede Zeile auszugeben und gleichzeitig zu überprüfen, und ein Flag setzen, wenn Ihre Nachricht gefunden wird. Wie es aussieht, wird Ihr Befehl, der auf der Nachricht basiert, erst ausgeführt, wenn die Ausgabe abgeschlossen ist. Ihre Frage gibt an, dass sie nicht asynchron ausgeführt werden kann. Wenn Sie jedoch Start-Job in PowerShell verwenden könnten, um ihn außerhalb des aktuellen Prozesses auszuführen, wenn Sie es benötigen, überprüfen Sie nach Abschluss der Ausgabe den Status des Jobs mit Get-Job. Shawn Melton vor 9 Jahren 0
0
AFH

Ich würde TCC / LE von JP Software empfehlen : Es implementiert viele der Funktionen von bash, einschließlich TEE, in CMD-kompatibler Syntax. In Ihrem Beispiel wäre das:

echo ee|tee con:|foo 

Ich habe mit dem folgenden Befehl getestet

for /l %n in (1,1,10) do ( echo %n %+ delay)|tee con:|nl. 

Hier ist NL ein Programm, das eine nummerierte Auflistung gibt, und die Ausgabe wurde nicht nummeriert und nummeriert. Die Verzögerung von 1 Sekunde erlaubte mir zu sehen, dass sowohl die Konsole als auch der Pipe Reader gleichzeitig Leitungen empfingen.

Die LE-Version ist für den privaten Gebrauch kostenlos.

Leider ist dies für meine spezielle Aufgabe weit vorbei. Wenn ich eine POSIX-Emulationsebene verwenden wollte, würde ich einfach MSYS oder cygwin verwenden. Außerdem hilft "tee" selbst nicht - es ist die Möglichkeit, auf das tty oder das Ausgabegerät umzuleiten, als wäre es eine Datei, die POSIX bereitstellt, und nicht den Befehl "tee". Bob vor 9 Jahren 0
TCC kann genau das: `echo ee | tee con: | foo` - Ich habe den folgenden Befehl getestet:` für / l% n in (1,1,10) do (Echo% n% + delay) | tee con: nl`. Hier ist NL ein Programm, das eine nummerierte Auflistung gibt, und die Ausgabe wurde nicht nummeriert und nummeriert. Die Verzögerung von 1 Sekunde erlaubte mir zu sehen, dass sowohl die Konsole als auch der Pipe Reader gleichzeitig Leitungen empfingen. Tut mir leid, dass Sie es für übertrieben halten: Ich wäre nicht ohne TCC. AFH vor 9 Jahren 0
Richtig - es wäre großartig, wenn Sie das in Ihre Antwort aufnehmen könnten (es ist nicht sofort offensichtlich, dass es eine Möglichkeit gibt, die Konsole zu referenzieren). Für meinen Fall noch übertrieben, da ich versuche, ein Build-Skript zu erstellen, das für die Versionskontrolle für andere Benutzer bestimmt ist. Ich möchte daher die Software von Drittanbietern minimieren, die ich bündeln muss (falls die Lizenz es überhaupt zulässt.) Redis). Eine kleine Binärdatei wie Benjis Antwort ist akzeptabel, ein vollständiger Befehlsinterpreter, den ich installieren muss, ist zu viel. Es könnte jedoch für andere Menschen nützlich sein. Bob vor 9 Jahren 0
Guter Punkt. Ich habe meine Antwort so aktualisiert, wie Sie es vorschlagen, und ich kann sehen, dass Benjis Lösung eine gute Lösung für Ihre speziellen Bedürfnisse ist, aber ich dachte, ich würde sie testen, und ich habe festgestellt, dass Sie `fflush (NULL);` after hinzufügen müssen die Zeile _fprintf () _, um die Ausgabe in Echtzeit anzuzeigen. Wenn Sie sich in einem kommerziellen Umfeld befinden, können Sie TCC nicht verwenden, ohne entsprechende Lizenzen zu erwerben. AFH vor 9 Jahren 0
0
Keltari

Sie können Ihre Batchdatei als PowerShell-Skript umschreiben. PowerShell hat Tee-Object(Alias ​​as Tee).

Parametersatz: Datei T-Objekt [-FilePath] [-Append] [-InputObject] []

Parametersatz: LiteralFile Tee-Object -LiteralPath [-InputObject] []

Parametersatz: Variable Tee-Object -Variable [-InputObject] []

Ja, das habe ich am Ende getan, mit dem in einer Selbstantwort beschriebenen Prozess. Fügt diese Antwort weitere Informationen hinzu? Bob vor 9 Jahren 0
-1
Jet

Legen Sie dies einfach auf eine Batchdatei (sagen wir mal echox.bat):

@echo off echo %1 echo %1|%2 

Dann nennen Sie diese Charge wie folgt:

echox 'c:\' dir 

Es wird ausgedruckt c:\und ausgegeben dir c:\.

HINWEIS: Da wir verwenden %1, %2müssen Parameter ohne Leerzeichen oder innerhalb von " "und übergeben werden ' '.

Bei Anwendung auf beliebige Probleme würde der Befehl zweimal ausgeführt werden, wobei die Ausgabe zum ersten Mal auf der Konsole gedruckt und das zweite Mal zum Ziel geleitet wird. Das funktioniert möglicherweise nicht, z. B. wenn der Befehl selbst den Status von Dateien usw. auf der Festplatte ändert. Thomas Weller vor 9 Jahren 1
@ThomasW, der Befehl wird nicht zweimal ausgeführt. Wie Sie sehen, druckt zunächst "echo% 1" nur den "% 1" -Parameter auf dem Bildschirm und der zweite "echo" sendet den "% 1" -Parameter an das "% 2" -Programm. Natürlich hat es einige Einschränkungen, löst aber im Allgemeinen das Problem. Jet vor 9 Jahren 0