Suprimir a saída da linha de comando

118

Eu tenho um arquivo em lote simples como este:

eco desligado

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

pausa

Se "test.exe" não estiver em execução, recebo esta mensagem:

ERRO: O processo "test.exe" não foi encontrado.

Por que essa mensagem de erro é exibida, embora eu tenha redirecionado a saída para NUL?

Como posso suprimir essa saída?

JosephStyons
fonte

Respostas:

212

Porque as mensagens de erro geralmente vão para stderrnão stdout.

Altere a invocação para:

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

e tudo ficará melhor.

Isso funciona porque stdouté o descritor de arquivo 1 e stderré o descritor de arquivo 2 por convenção. (0 é stdin, aliás.) As 2>&1cópias geram a saída do descritor 2 do novo valor 1, que foi redirecionado para o dispositivo nulo.

Esta sintaxe é (vagamente) emprestada de muitos shells Unix, mas você deve ter cuidado porque existem diferenças sutis entre a sintaxe do shell e CMD.EXE.

Atualização: eu sei que o OP entende a natureza especial do "arquivo" chamado para o qual NULestou escrevendo aqui, mas um comentarista não entendeu e, portanto, deixe-me divagar com mais detalhes sobre esse aspecto.

Voltando às primeiras versões do MSDOS, certos nomes de arquivos foram substituídos pelo kernel do sistema de arquivos e usados ​​para se referir a dispositivos. A lista mais antigo desses nomes incluídos NUL, PRN, CON, AUXe COM1através COM4. NULé o dispositivo nulo. Ele sempre pode ser aberto para leitura ou gravação, qualquer valor pode ser escrito nele e as leituras sempre são bem-sucedidas, mas não retornam dados. Os outros incluem a porta paralela da impressora, o console e até quatro portas seriais. No MSDOS 5, havia vários outros nomes reservados, mas a convenção básica estava muito bem estabelecida.

Quando o Windows foi criado, ele começou como uma camada bastante fina de troca de aplicativos sobre o kernel do MSDOS e, portanto, tinha as mesmas restrições de nome de arquivo. Quando o Windows NT foi criado como um verdadeiro sistema operacional por si só, nomes como NULe COM1foram amplamente considerados para funcionar para permitir sua eliminação. No entanto, a ideia de que novos dispositivos sempre receberiam nomes que bloqueariam o futuro usuário desses nomes para arquivos reais é obviamente irracional.

O Windows NT e todas as versões seguintes (2K, XP, 7 e agora 8) usam o namespace NT muito mais elaborado do código do kernel e para código de espaço do usuário cuidadosamente construído e altamente não portátil. Nesse espaço de nome, os drivers de dispositivo são visíveis por meio da \Devicepasta. Para oferecer suporte à compatibilidade com versões anteriores exigida, há um mecanismo especial usando a \DosDevicespasta que implementa a lista de nomes de arquivos reservados em qualquer pasta do sistema de arquivos. O código do usuário pode navegar neste espaço de nome interno usando uma camada de API abaixo da API Win32 usual; uma boa ferramenta para explorar o namespace do kernel é WinObj do grupo SysInternals da Microsoft.

Para obter uma descrição completa das regras que envolvem os nomes legais de arquivos (e dispositivos) no Windows, esta página do MSDN será informativa e assustadora. As regras são muito mais complicadas do que deveriam ser e, na verdade, é impossível responder a algumas perguntas simples como "qual é o comprimento do nome de caminho totalmente qualificado legal mais longo?".

RBerteig
fonte
5
Obrigado pela resposta e, acima de tudo, pela explicação.
JosephStyons
Uma recomendação: taskkill /im "test.exe" /f >%temp%\nul 2>&1 & del %temp%\nul. Isso impedirá que um arquivo nulo em branco seja colocado no diretório local
Samy Bencherif
11
@SamyBencherif, NULé um nome de arquivo reservado e mapeia para o dispositivo NUL. Você não pode criar um arquivo real nomeado NULem qualquer diretório.
RBerteig
7

Em vez disso, use este script:

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

O que a 2>&1parte realmente faz é redirecionar a stderrsaída para stdout. Vou explicar melhor a seguir:

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

Mate a tarefa "test.exe". Redirecionar stderrpara stdout. Em seguida, redirecione stdoutpara nul.

@pausa

Mostra a mensagem de pausa Press any key to continue . . . até que alguém pressione uma tecla.

NOTA: O @símbolo está ocultando o prompt de cada comando. Você pode economizar até 8 bytes dessa forma.

A versão mais curta do seu script pode ser:
@taskkill/f /im test.exe >nul 2>&1&pause
O &caractere é usado para redirecionar na primeira vez e para separar os comandos na segunda vez.
Um @personagem não é necessário duas vezes em uma linha. Este código tem apenas 40 bytes, apesar do que você postou ter 49 bytes! Na verdade, salvei 9 bytes. Para um código mais limpo, olhe acima.

EKons
fonte
Sim, eu sei que metade da postagem é na verdade como encurtar seu código.
EKons de
3

mysqldump não funciona com: > nul 2> & 1
Em vez disso, use: 2> nul
Isso suprime a mensagem stderr: "Aviso: Usar uma senha na interface de linha de comando pode ser inseguro"

margenn
fonte
0

Você também pode fazer isso:

tasklist | find /I "test.exe" > nul && taskkill /f /im test.exe > nul
yoman
fonte
Apesar de o contexto da pergunta ser scripts em lote, descobri que no PowerShell a sintaxe acima falha com " out-file: FileStream foi solicitado a abrir um dispositivo que não era um arquivo. Para suporte para dispositivos como 'com1:' ou 'lpt1: ', chame CreateFile e use os construtores FileStream que usam um identificador de SO como IntPtr. "A solução é substituir > nulpor >$null.
açude