Suprimir la salida de la línea de comando

118

Tengo un archivo por lotes simple como este:

eco apagado

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

pausa

Si "test.exe" no se está ejecutando, aparece este mensaje:

ERROR: No se encontró el proceso "test.exe".

¿Por qué aparece este mensaje de error, aunque he redirigido la salida a NUL?

¿Cómo puedo suprimir esa salida?

JosephStyons
fuente

Respuestas:

212

Debido a que los mensajes de error a menudo stderrnostdout .

Cambie la invocación a esto:

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

y todo irá mejor.

Eso funciona porque stdoutes el descriptor de archivo 1 y stderres el descriptor de archivo 2 por convención. (0 es stdin, dicho sea ​​de paso.) El 2>&1descriptor de archivo de salida de copias 2 del nuevo valor de 1, que acaba de ser redirigido al dispositivo nulo.

Esta sintaxis se toma prestada (libremente) de muchos shells de Unix, pero debe tener cuidado porque hay diferencias sutiles entre la sintaxis de shell y CMD.EXE.

Actualización: Sé que el OP entiende la naturaleza especial del "archivo" llamado al NULque estoy escribiendo aquí, pero un comentarista no lo hizo, así que permítanme divagar con un poco más de detalle sobre ese aspecto.

Remontándonos hasta las primeras versiones de MSDOS, el kernel del sistema de archivos se apropió de ciertos nombres de archivo y se usaron para hacer referencia a dispositivos. La primera lista de los nombres incluidos NUL, PRN, CON, AUXy COM1a través COM4. NULes el dispositivo nulo. Siempre se puede abrir para leer o escribir, se puede escribir cualquier cantidad en él, y las lecturas siempre se realizan correctamente pero no devuelven datos. Los otros incluyen el puerto de impresora paralelo, la consola y hasta cuatro puertos seriales. A partir de MSDOS 5, había varios nombres más reservados, pero la convención básica estaba muy bien establecida.

Cuando se creó Windows, comenzó su vida como una capa de conmutación de aplicaciones bastante delgada sobre el kernel de MSDOS y, por lo tanto, tenía las mismas restricciones de nombre de archivo. Cuando se creó Windows NT como un verdadero sistema operativo por derecho propio, se asumió demasiado ampliamente que los nombres como NULy COM1funcionaban como para permitir su eliminación. Sin embargo, la idea de que los nuevos dispositivos siempre obtendrían nombres que bloquearían a los futuros usuarios de esos nombres para archivos reales es obviamente irrazonable.

Windows NT y todas las versiones siguientes (2K, XP, 7 y ahora 8) utilizan el espacio de nombres NT mucho más elaborado del código del kernel y un código de espacio de usuario cuidadosamente construido y altamente no portátil. En ese espacio de nombres, los controladores de dispositivos son visibles a través de la \Devicecarpeta. Para admitir la compatibilidad con versiones anteriores requerida, existe un mecanismo especial que utiliza la \DosDevicescarpeta que implementa la lista de nombres de archivos reservados en cualquier carpeta del sistema de archivos. El código de usuario puede examinar este espacio de nombres interno utilizando una capa de API debajo de la API Win32 habitual; una buena herramienta para explorar el espacio de nombres del kernel es WinObj del grupo SysInternals de Microsoft.

Para obtener una descripción completa de las reglas que rodean los nombres legales de archivos (y dispositivos) en Windows, esta página en MSDN será informativa y desalentadora. Las reglas son mucho más complicadas de lo que deberían ser, y en realidad es imposible responder algunas preguntas simples como "¿cuánto tiempo es el nombre de ruta legal completamente calificado más largo?".

RBerteig
fuente
5
Gracias por la respuesta y, sobre todo, por la explicación.
JosephStyons
Una recomendación: taskkill /im "test.exe" /f >%temp%\nul 2>&1 & del %temp%\nul. Esto evitará que se coloque un archivo nulo en blanco en el directorio local
Samy Bencherif
11
@SamyBencherif, NULes un nombre de archivo reservado y se asigna al dispositivo NUL. No puede crear un archivo real con un nombre NULen ningún directorio.
RBerteig
7

Utilice este script en su lugar:

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

Lo que 2>&1realmente hace la pieza es redirigir la stderrsalida a stdout. Lo explicaré mejor a continuación:

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

Elimine la tarea "test.exe". Redirigir stderra stdout. Luego, redirigir stdouta nul.

@pausa

Muestre el mensaje de pausa Press any key to continue . . . hasta que alguien presione una tecla.

NOTA: El @símbolo oculta la solicitud de cada comando. Puede guardar hasta 8 bytes de esta manera.

La versión más corta de su secuencia de comandos podría ser:
@taskkill/f /im test.exe >nul 2>&1&pause
El &carácter se usa para la redirección la primera vez y para separar los comandos la segunda vez.
No @se necesita un carácter dos veces en una línea. ¡Este código tiene solo 40 bytes, a pesar de que el que ha publicado tiene 49 bytes! De hecho, guardé 9 bytes. Para un código más limpio, mire arriba.

EKons
fuente
Sí, sé que la mitad de la publicación es en realidad cómo acortar su código.
EKons
3

mysqldump no funciona con: > nul 2> & 1
En su lugar, use: 2> nul
Esto suprime el mensaje stderr: "Advertencia: Usar una contraseña en la interfaz de línea de comandos puede ser inseguro"

margenn
fuente
0

También puedes hacer esto en su lugar:

tasklist | find /I "test.exe" > nul && taskkill /f /im test.exe > nul
yoman
fuente
A pesar de que el contexto de la pregunta eran scripts por lotes, encontré que en PowerShell la sintaxis anterior falla con " out-file: se le pidió a FileStream que abriera un dispositivo que no era un archivo. Para compatibilidad con dispositivos como 'com1:' o 'lpt1: ', llame a CreateFile, luego use los constructores FileStream que toman un identificador de SO como un IntPtr. "La solución es reemplazar > nulcon >$null.
vertedero