O redirecionamento de saída do Windows cmd para a entrada padrão (& 0)

4

De uma pergunta no Stackoverflow, estou testando com redirecionamento de / para o fluxo de stdin. E esses testes, tentando enviar dados para o fluxo de stdin, apenas para ver o que acontece, terminam com um comportamento aparentemente caótico.

Comandos como

echo testing >&0
dir >&0 
cls >&0

irá gerar um System can not write to the specified device (parece que o stdin é um fluxo somente de leitura, talvez), mas coisas como

  • vol >&0 não mostra nenhum erro

  • set /p "var=prompt" >&0 aguarda a entrada enquanto não mostra o prompt e não mostra nenhum erro

  • pause >&0 aguardará sem erro, mas quando uma tecla é pressionada, o erro é exibido

E a última gota é o redirecionamento stderr. Ao usar comandos internos que enviam saída para stderr com ele redirecionado para stdin, como

call "noFile" 2>&0
dir  "|" 2>&0

o resultado é que o cmd.exe será fechado. Mas não sempre. Coisas como

dir "|" * 2>&0
dir * "|" 2>&0

trabalhe sem problemas, escondendo o texto enviado ao stderr e imprimindo o resto da informação.

Então, a questão é, isso é um bug, está documentado em algum lugar e eu não consigo encontrá-lo ou esse é o comportamento esperado e há algo óbvio que estou perdendo?

    
por MC ND 29.08.2014 / 12:32

3 respostas

4

Dado que o CMD.EXE está insuficientemente documentado, não sei qual deve ser o comportamento esperado. Eu certamente não vi nenhuma documentação sobre qual é o comportamento esperado. Então, acho que você será duramente pressionado para encontrar alguém que possa dar uma resposta definitiva sobre se algum dos comportamentos é um bug. Mas eu concordo que certamente é inconsistente, e parece pelo menos uma falha de design para mim.

Eu não caracterizaria a situação como caótica, pois o comportamento de um determinado comando parece ser reproduzível. Mas o CMD.EXE é inconsistente, pois não consigo prever como qualquer comando se comporta sem testar.

Eu não tenho explicações, mas tenho algumas classificações refinadas de comportamentos.

O redirecionamento de stdout ou stderr para stdin funciona perfeitamente, contanto que nenhum comando realmente tente escrever qualquer coisa na saída redirecionada. O comportamento estranho só ocorre quando um comando interno tenta gravar em stdout ou stderr depois de ter sido redirecionado para stdin.

Eu estendi seus testes e vi os seguintes comportamentos distintos:

STDERR redirecionado 2>&01

Eu não fiz testes exaustivos, mas todo comando interno que testei e grava em stderr terminará imediatamente a sessão de comando se stderr for redirecionado para stdin. Exemplos incluem:

cd invalidPath 2>&0
vol x 2>&0
copy nonExistentFile 2>&0
move nonExistentFile 2>&0
set nonExistentVariable 2>&0
dir nonExistentFile 2>&0

O que você achava que era uma exceção, na verdade nunca grava em stderr. Tente o seguinte sem redirecionamento e você verá que não há mensagem de erro:

dir nonExistentFIle *

Portanto, não há razão para o comando encerrar a sessão de comando se o stderr for redirecionado para stdin.

O DIR imprime apenas uma mensagem de erro se não encontrar nenhum arquivo correspondente em todas as máscaras de arquivo fornecidas.

:: This prints an error message
dir nonExistentFile1 nonExistentFile2

:: So this terminates the command session
dir nonExistentFile1 nonExistentFile2 2>&0


Redirecionado STDOUT 1>&0

Aqui estão os comportamentos que vi para a stdout redirecionada:

1) A saída desaparece no éter, sem qualquer mensagem de erro.

Exemplos:

vol >&0
copy /-y file1 existingFile2 >&0
move /-y file1 existingFile2 >&0


2) A saída falha e uma mensagem de erro é exibida para stderr. Um único comando pode gerar várias mensagens de falha, uma para cada tentativa malsucedida de gravar no stdout.

Exemplos:

cd >&0
echo Hello >&0

:: This generates 2 error messages, one for the time,
:: and another for the subsequent empty line
time /t >&0


3) A saída falha e o processamento em lote é finalizado. SETLOCAL ativo permanece em vigor, mesmo após o término do lote, se o erro ocorrer dentro de uma sub-rotina chamada. A este respeito, comporta-se muito como um erro de sintaxe fatal.

Até agora, só vi um comando exibir esse comportamento:

dir >&0

Espero que o comando DIR gere uma mensagem de erro para cada linha de saída tentada. Mas parece terminar depois de falhar na primeira linha, e o processamento em lote também é abortado.


4) Alguns comandos exibem vários comportamentos.

Exemplos:

:: This SET command generates an error message for each
:: defined variable (behavior 2)
set >&0

:: But this SET command fails to display the prompt without
:: error message (behavior 1). Note that the echo of user input
:: is written directly to :con. It does not use stdout or stderr.
set "var=prompt" >&0

:: A single PAUSE exhibits both behaviors 1 and 2. The prompt to
:: press a key simply dissapears, and the echo of the user input
:: generates an error. Note that in this case, the echo of user
:: input is written to stdout.
pause >&0
    
por 01.09.2014 / 06:23
0

Eu descobri esse bug por engano em 2010. Eu finalmente descobri o meu erro - redirecionar stderr para o fluxo 0 (stdin para o processo atual) não faz sentido lógico, e o cmd.exe não tinha um manipulador para esse cenário, então apenas se salvou. A sintaxe correta foi:

dir 2 > nul (se eu quisesse apenas redirecionar o erro)

ou

dir 2 > nul 1 > & 2 (se eu também quisesse redirecionar a saída bem-sucedida).

Basicamente apenas uma exceção não tratada no CMD.EXE para qualquer comando interno. Aqui está o meu artigo de alguns anos atrás: link

    
por 21.05.2015 / 16:14
0

Dê uma olhada no link

>& Writes the output from one handle to the input of another handle.
<& Reads the input from one handle and writes it to the output of another handle.

The & redirection operator duplicates output or input from one specified handle to another specified handle. When you duplicate a handle, you duplicate all characteristics of the original occurrence of the handle. For example, if a handle has write-only access, all duplicates of that handle have write-only access. You cannot duplicate a handle with read-only access into a handle with write-only access.

    
por 21.04.2016 / 13:21