Pomiń wyjście wiersza poleceń

118

Mam prosty plik wsadowy, taki jak ten:

echo wyłączone

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

pauza

Jeśli „test.exe” nie jest uruchomiony, pojawia się następujący komunikat:

BŁĄD: Nie znaleziono procesu „test.exe”.

Dlaczego ten komunikat o błędzie jest wyświetlany, mimo że przekierowałem dane wyjściowe do NUL?

Jak mogę ukryć to wyjście?

JosephStyons
źródło

Odpowiedzi:

212

Ponieważ komunikaty o błędach często stderrnie stdout.

Zmień wywołanie na to:

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

i wszystko będzie lepsze.

To działa, ponieważ stdoutjest deskryptorem pliku 1, a stderrzgodnie z konwencją jest deskryptorem pliku 2. ( stdinNawiasem mówiąc, 0 to .) 2>&1Kopiuje deskryptor pliku wyjściowego 2 z nowej wartości 1, która została właśnie przekierowana na urządzenie zerowe.

Ta składnia jest (luźno) zapożyczona z wielu powłok Uniksa, ale musisz być ostrożny, ponieważ istnieją subtelne różnice między składnią powłoki a CMD.EXE.

Aktualizacja: Wiem, że OP rozumie specjalną naturę „pliku” o nazwie NUL, do której tu piszę, ale komentator tego nie zrobił, więc pozwólcie mi na dygresję, podając trochę więcej szczegółów na ten temat.

Wracając do najwcześniejszych wersji MSDOS, niektóre nazwy plików były wywłaszczane przez jądro systemu plików i używane w odniesieniu do urządzeń. Najwcześniejszym lista tych nazw włączone NUL, PRN, CON, AUXi COM1dzięki COM4. NULjest urządzeniem zerowym. Zawsze można go otworzyć do odczytu lub zapisu, można na nim zapisać dowolną ilość, a odczyt zawsze kończy się pomyślnie, ale nie zwraca żadnych danych. Pozostałe obejmują port równoległy drukarki, konsolę i do czterech portów szeregowych. Począwszy od MSDOS 5, było kilka bardziej zastrzeżonych nazw, ale podstawowa konwencja była bardzo dobrze ugruntowana.

Kiedy powstał system Windows, zaczął istnieć jako dość cienka warstwa przełączająca aplikacje na wierzchu jądra MSDOS, a zatem miała te same ograniczenia dotyczące nazw plików. Kiedy Windows NT został stworzony jako prawdziwy system operacyjny na swoich własnych prawach, nazwy takie jak NULi COM1były zbyt szeroko zakładane, aby umożliwić ich eliminację. Jednak pomysł, że nowe urządzenia zawsze otrzymywałyby nazwy, które blokowałyby przyszłego użytkownika tych nazw dla rzeczywistych plików, jest oczywiście nieracjonalny.

Windows NT i wszystkie następujące po nim wersje (2K, XP, 7, a teraz 8) wykorzystują znacznie bardziej rozbudowaną przestrzeń nazw NT od kodu jądra po starannie skonstruowany i wysoce nieprzenośny kod przestrzeni użytkownika. W tej przestrzeni nazw sterowniki urządzeń są widoczne za pośrednictwem \Devicefolderu. Aby zapewnić wymaganą kompatybilność wsteczną, istnieje specjalny mechanizm wykorzystujący \DosDevicesfolder, który implementuje listę zarezerwowanych nazw plików w dowolnym folderze systemu plików. Kod użytkownika może przeglądać tę wewnętrzną przestrzeń nazw za pomocą warstwy API poniżej zwykłego API Win32; dobrym narzędziem do eksploracji przestrzeni nazw jądra jest WinObj z grupy SysInternals w firmie Microsoft.

Aby uzyskać pełny opis zasad dotyczących nazw prawnych plików (i urządzeń) w systemie Windows, ta strona w witrynie MSDN będzie zawierała zarówno informacje, jak i zniechęcenie. Zasady są o wiele bardziej skomplikowane, niż powinny, i właściwie nie można odpowiedzieć na kilka prostych pytań, takich jak „jak długa jest najdłuższa prawnie w pełni kwalifikowana nazwa ścieżki?”.

RBerteig
źródło
5
Dziękuję za odpowiedź, a przede wszystkim za wyjaśnienie.
JosephStyons,
Zalecenie: taskkill /im "test.exe" /f >%temp%\nul 2>&1 & del %temp%\nul. Zapobiegnie to umieszczeniu pustego pustego pliku w katalogu lokalnym
Samy Bencherif
11
@SamyBencherif NULto zarezerwowana nazwa pliku, która jest mapowana na urządzenie NUL. Nie można utworzyć rzeczywistego pliku o nazwie NULw żadnym katalogu.
RBerteig
7

Zamiast tego użyj tego skryptu:

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

To, co 2>&1faktycznie robi część, to przekierowywanie danych stderrwyjściowych do stdout. Poniżej wyjaśnię to lepiej:

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

Zabij zadanie „test.exe”. Przekieruj stderrdo stdout. Następnie przekieruj stdoutdo nul.

@pauza

Wyświetlaj komunikat wstrzymania, Press any key to continue . . . dopóki ktoś nie naciśnie klawisza.

UWAGA: @Symbol ukrywa monit dla każdego polecenia. W ten sposób możesz zaoszczędzić do 8 bajtów.

Najkrótsza wersja skryptu może być: znak jest używany do przekierowania po raz pierwszy, a do oddzielania poleceń po raz drugi. Znak nie jest potrzebny dwa razy w linii. Ten kod ma tylko 40 bajtów, mimo że ten, który opublikowałeś, ma 49 bajtów! W rzeczywistości zaoszczędziłem 9 bajtów. Bardziej przejrzysty kod znajdziesz powyżej.
@taskkill/f /im test.exe >nul 2>&1&pause
&
@

EKons
źródło
Tak, wiem, że połowa postu to właściwie jak skrócić kod.
EKon
3

mysqldump nie działa z: > nul 2> & 1
Zamiast tego użyj: 2> nul
To pomija komunikat stderr: "Ostrzeżenie: Używanie hasła w interfejsie wiersza poleceń może być niebezpieczne"

margenn
źródło
0

Zamiast tego możesz to zrobić:

tasklist | find /I "test.exe" > nul && taskkill /f /im test.exe > nul
yoman
źródło
Niezależnie od tego, że kontekstem pytania były skrypty wsadowe, zauważyłem, że w PowerShell powyższa składnia zawodzi z komunikatem „ out-file: FileStream został poproszony o otwarcie urządzenia, które nie jest plikiem. W celu obsługi urządzeń takich jak„ com1: ”lub„ lpt1: ', wywołaj CreateFile, a następnie użyj konstruktorów FileStream, które przyjmują uchwyt systemu operacyjnego jako IntPtr. ”Rozwiązaniem jest zastąpienie > nulprzez >$null.
jaz