Подавить вывод командной строки

118

У меня есть такой простой командный файл:

эхо выключено

taskkill / im "test.exe" / f> нуль

Пауза

Если "test.exe" не запущен, я получаю следующее сообщение:

ОШИБКА: процесс test.exe не найден.

Почему отображается это сообщение об ошибке, даже если я перенаправил вывод на NUL?

Как я могу подавить этот вывод?

JosephStyons
источник

Ответы:

212

Потому что сообщения об ошибках часто отправляются в stderrnot stdout.

Измените вызов на это:

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

и все будет лучше.

Это работает, потому что stdoutэто дескриптор файла 1 и stderrдескриптор файла 2 по соглашению. (Кстати stdin, 0. ) 2>&1Дескриптор выходного файла 2 копируется из нового значения 1, которое было только что перенаправлено на нулевое устройство.

Этот синтаксис (вольно) заимствован из многих оболочек Unix, но вы должны быть осторожны, потому что есть тонкие различия между синтаксисом оболочки и CMD.EXE.

Обновление: я знаю, что OP понимает особую природу «файла» с именем, в NULкоторый я пишу здесь, но комментатор этого не сделал, поэтому позвольте мне отвлечься и рассказать немного подробнее об этом аспекте.

Возвращаясь к самым ранним выпускам MSDOS, определенные имена файлов вытеснялись ядром файловой системы и использовались для обозначения устройств. Самый ранний список этих имен , включенных NUL, PRN, CON, AUXи COM1через COM4. NUL- нулевое устройство. Его всегда можно открыть для чтения или записи, на нем можно записать любую сумму, чтение всегда проходит успешно, но не возвращает данных. К другим относятся параллельный порт принтера, консоль и до четырех последовательных портов. Начиная с MSDOS 5, было еще несколько зарезервированных имен, но основное соглашение было очень хорошо установлено.

Когда была создана Windows, она начала свою жизнь как довольно тонкий слой переключения приложений поверх ядра MSDOS и, следовательно, имела те же ограничения на имя файла. Когда Windows NT создавалась как настоящая операционная система сама по себе, такие имена, как NULи COM1были слишком широко распространены, чтобы их можно было устранить. Однако идея о том, что новые устройства всегда будут получать имена, которые будут блокировать будущие пользователи этих имен для реальных файлов, очевидно, неразумна.

Windows NT и все последующие версии (2K, XP, 7 и теперь 8) используют гораздо более сложное пространство имен NT, начиная с кода ядра и заканчивая тщательно разработанным и очень непереносимым кодом пользовательского пространства. В этом пространстве имен драйверы устройств видны через \Deviceпапку. Для поддержки требуемой обратной совместимости существует специальный механизм, использующий \DosDevicesпапку, который реализует список зарезервированных имен файлов в любой папке файловой системы. Пользовательский код может просматривать это внутреннее пространство имен, используя уровень API ниже обычного Win32 API; Хорошим инструментом для изучения пространства имен ядра является WinObj от группы SysInternals в Microsoft.

Чтобы получить полное описание правил, касающихся законных имен файлов (и устройств) в Windows, эта страница в MSDN будет как информативной, так и пугающей. Правила намного сложнее, чем они должны быть, и на самом деле невозможно ответить на некоторые простые вопросы, такие как «какова длина самого длинного допустимого полного имени пути?».

RBerteig
источник
5
Спасибо за ответ и больше всего за объяснение.
JosephStyons,
Рекомендация: taskkill /im "test.exe" /f >%temp%\nul 2>&1 & del %temp%\nul. Это предотвратит размещение пустого нулевого файла в локальном каталоге
Сами Бенчериф
11
@SamyBencherif NUL- это зарезервированное имя файла, которое соответствует устройству NUL. Вы не можете создать настоящий файл с именем NULв каком-либо каталоге.
RBerteig
7

Вместо этого используйте этот сценарий:

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

Что на 2>&1самом деле делает эта часть, так это то, что она перенаправляет stderrвывод в stdout. Я объясню это лучше ниже:

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

Убиваем задачу "test.exe". Перенаправить stderrна stdout. Затем перенаправьте stdoutна nul.

@Пауза

Показывать сообщение о паузе, Press any key to continue . . . пока кто-нибудь не нажмет клавишу.

ПРИМЕЧАНИЕ. @Символ скрывает приглашение для каждой команды. Таким образом можно сэкономить до 8 байт.

Самая короткая версия вашего сценария может быть: символ используется для перенаправления в первый раз, и для разделения команд , во второй раз. Символ не требуется дважды в одну линию. Этот код составляет всего 40 байтов, хотя тот, который вы опубликовали, составляет 49 байтов! На самом деле я сэкономил 9 байт. Более чистый код смотрите выше.
@taskkill/f /im test.exe >nul 2>&1&pause
&
@

EKons
источник
Да, я знаю, что половина поста посвящена сокращению кода.
EKons
3

mysqldump не работает с: > nul 2> & 1
Вместо этого используйте: 2> nul
Это подавляет сообщение stderr: «Предупреждение: использование пароля в интерфейсе командной строки может быть небезопасным»

margenn
источник
0

Вы также можете сделать это:

tasklist | find /I "test.exe" > nul && taskkill /f /im test.exe > nul
Йоу, чувак
источник
Несмотря на то, что контекстом вопроса были пакетные сценарии, я обнаружил, что в PowerShell указанный выше синтаксис не работает с " out-file: FileStream" попросили открыть устройство, которое не было файлом. Для поддержки таких устройств, как 'com1:' или 'lpt1: ', вызовите CreateFile, а затем используйте конструкторы FileStream, которые принимают дескриптор ОС как IntPtr. «Решение состоит в замене > nulна >$null.
плотина