Befehlszeilenausgabe unterdrücken

118

Ich habe eine einfache Batch-Datei wie diese:

Echo aus

taskkill / im "test.exe" / f> nul

Pause

Wenn "test.exe" nicht ausgeführt wird, wird folgende Meldung angezeigt:

FEHLER: Der Prozess "test.exe" wurde nicht gefunden.

Warum wird diese Fehlermeldung angezeigt, obwohl ich die Ausgabe an NUL umgeleitet habe?

Wie kann ich diese Ausgabe unterdrücken?

JosephStyons
quelle

Antworten:

212

Da Fehlermeldungen gehen oft stderrnicht stdout.

Ändern Sie den Aufruf in:

taskkill /im "test.exe" /f >nul 2>&1

und alles wird besser.

Das funktioniert, weil stdoutes sich um Dateideskriptor 1 und stderrgemäß Konvention um Dateideskriptor 2 handelt. (0 ist stdinübrigens.) Der 2>&1kopiert den Ausgabedateideskriptor 2 vom neuen Wert 1, der gerade auf das Nullgerät umgeleitet wurde.

Diese Syntax ist (lose) von vielen Unix-Shells entlehnt, aber Sie müssen vorsichtig sein, da es subtile Unterschiede zwischen der Shell-Syntax und CMD.EXE gibt.

Update: Ich weiß , dass die OP versteht den besonderen Charakter der „Datei“ genannt NULIch bin hier zu schreiben, aber ein Kommentator nicht und so lassen Sie mich auf diesen Aspekt mit ein wenig mehr Details abzuschweifen.

Zurück zu den frühesten Versionen von MSDOS wurden bestimmte Dateinamen vom Dateisystemkernel vorbelegt und verwendet, um auf Geräte zu verweisen. Die früheste Liste der Namen enthalten NUL, PRN, CON, AUXund COM1durch COM4. NUList das Nullgerät. Es kann immer zum Lesen oder Schreiben geöffnet werden, es kann ein beliebiger Betrag darauf geschrieben werden, und Lesevorgänge sind immer erfolgreich, geben jedoch keine Daten zurück. Zu den anderen gehören der parallele Druckeranschluss, die Konsole und bis zu vier serielle Anschlüsse. Ab MSDOS 5 gab es mehrere reservierte Namen, aber die Grundkonvention war sehr gut etabliert.

Als Windows erstellt wurde, begann es als ziemlich dünne Anwendungswechselschicht über dem MSDOS-Kernel und hatte daher dieselben Dateinamenbeschränkungen. Als Windows NT als eigenständiges echtes Betriebssystem erstellt wurde, wurde angenommen , dass Namen wie NULund COM1zu weit verbreitet sind, um ihre Beseitigung zu ermöglichen. Die Idee, dass neue Geräte immer Namen erhalten, die zukünftige Benutzer dieser Namen für tatsächliche Dateien blockieren, ist jedoch offensichtlich unvernünftig.

Windows NT und alle folgenden Versionen (2K, XP, 7 und jetzt 8) verwenden den viel ausgefeilteren NT-Namespace aus dem Kernel-Code und sorgfältig konstruierten und höchst nicht portierbaren Benutzerbereichscodes. In diesem Namensraum sind Gerätetreiber im \DeviceOrdner sichtbar . Um die erforderliche Abwärtskompatibilität zu unterstützen, gibt es einen speziellen Mechanismus, der den \DosDevicesOrdner verwendet, der die Liste der reservierten Dateinamen in einem beliebigen Dateisystemordner implementiert. Benutzercode kann diesen internen Namensraum mithilfe einer API-Ebene unterhalb der üblichen Win32-API durchsuchen. Ein gutes Tool zum Erkunden des Kernel-Namespace ist WinObj von der SysInternals-Gruppe bei Microsoft.

Eine vollständige Beschreibung der Regeln für legale Namen von Dateien (und Geräten) in Windows finden Sie auf dieser Seite von MSDN sowohl informativ als auch entmutigend. Die Regeln sind viel komplizierter als sie sein sollten, und es ist tatsächlich unmöglich, einige einfache Fragen zu beantworten, wie z. B. "Wie lange ist der längste legale, vollständig qualifizierte Pfadname?".

RBerteig
quelle
5
Danke für die Antwort und vor allem für die Erklärung.
JosephStyons
Eine Empfehlung : taskkill /im "test.exe" /f >%temp%\nul 2>&1 & del %temp%\nul. Dies verhindert, dass eine leere Nulldatei in das lokale Verzeichnis gestellt wird
Samy Bencherif
11
@SamyBencherif NUList ein reservierter Dateiname und wird dem NUL-Gerät zugeordnet. Sie können keine tatsächliche Datei mit einem Namen NULin einem Verzeichnis erstellen .
RBerteig
7

Verwenden Sie stattdessen dieses Skript:

@taskkill/f /im test.exe >nul 2>&1
@pause

Was der 2>&1Teil tatsächlich tut, ist, dass er die stderrAusgabe an umleitet stdout. Ich werde es unten besser erklären:

@ taskkill / f / im test.exe> ​​nul 2> & 1

Töte die Aufgabe "test.exe". Weiterleiten stderran stdout. Weiterleiten stdoutan nul.

@Pause

Zeigen Sie die Pausenmeldung an, Press any key to continue . . . bis jemand eine Taste drückt.

HINWEIS: Das @Symbol verbirgt die Eingabeaufforderung für jeden Befehl. Auf diese Weise können Sie bis zu 8 Bytes speichern.

Die kürzeste Version Ihres Skripts könnte sein:
@taskkill/f /im test.exe >nul 2>&1&pause
Das &Zeichen wird beim ersten Mal zur Umleitung und beim zweiten Mal zum Trennen der Befehle verwendet.
Ein @Zeichen wird nicht zweimal in einer Zeile benötigt. Dieser Code ist nur 40 Bytes, obwohl der von Ihnen gepostete 49 Bytes ist! Ich habe tatsächlich 9 Bytes gespeichert. Für einen saubereren Code siehe oben.

EKons
quelle
Ja, ich weiß, dass die Hälfte des Beitrags tatsächlich darin besteht, Ihren Code zu verkürzen.
EKons
3

mysqldump funktioniert nicht mit: > nul 2> & 1
Verwenden Sie stattdessen: 2> nul
Dies unterdrückt die stderr-Meldung: "Warnung: Die Verwendung eines Kennworts auf der Befehlszeilenschnittstelle kann unsicher sein."

margenn
quelle
0

Sie können dies stattdessen auch tun:

tasklist | find /I "test.exe" > nul && taskkill /f /im test.exe > nul
Yoman
quelle
Ungeachtet dessen, dass der Kontext der Frage Batch-Skripte waren, stellte ich fest, dass in PowerShell die obige Syntax mit " out-file: FileStream " fehlschlägt, um ein Gerät zu öffnen, das keine Datei ist. Zur Unterstützung von Geräten wie 'com1:' oder 'lpt1: ‘, rufen Sie Createfile, dann verwenden Sie die Filestream - Konstrukteure , die ein OS Griff als IntPtr nehmen. " Die Lösung ist zu ersetzen > nulmit >$null.
Wehr