Redirecionamento de entrada: como fazer no Windows Powershell e no CMD

Olá,

Primeiramente gostaria de pedir desculpas pelos atrasos. Estive com problemas, compromissos em São Paulo e, ultimamente, doente, com uma virose que me deixou de cama. Agora estou melhor.

Recentemente conversando com um amigo me deparei com um recurso muito legal que existia no antigo CMD e não foi implementado no Powershell. O redirecionamento da entrada de um programa, truque muito usado por nós na universidade para testar pequenos programas em várias linguagens de programação, desde C e C++ até Java, Ruby, Python e Perl.

O truque é bem simples: imagine que você tem um programa bem simples que precisa ser testado. No entanto, você ainda está desenvolvendo e precisa testar várias vezes. Ao invés de executar e digitar a entrada do programa manualmente, você pode utilizar um arquivo texto, que vai simular a entrada do programa normalmente. Cada caractere será pressionado e ao final da linha, será pressionada a tecla Enter, normalmente.

Abaixo, tenho um exemplo de um programa em Ruby. Poderia ser qualquer outra linguagem...

begin
a = gets
puts a.upcase
end until a == "\n"

A propósito, tudo que o código acima faz esperar que o usuário digite algum texto em uma linha e reimprimir esse texto até que ele não digite nada e pressione um Enter. Você pode testar esse programa digitando algumas linhas e pressionando Enter... ou colocá-las em um arquivo texto, como por exemplo o arquivo abaixo, o teste.in:

vinicius
teste
teste_com_numeros_243523452435
áéíóúçãoi:ü'áà

Agora, para rodar o programa usando o arquivo salvo:

ruby programa.rb < teste.in

Isso funciona em qualquer emulador de terminal Unix/Linux e mesmo no Windows, no CMD.EXE. As únicas exceções são o COMMAND.COM e o Powershell, que não teve esse recurso implementado. Ao digitar o comando acima, você vai receber a seguinte mensagem:

Sr.Canto@VMACHINE Ruby# ruby programa.rb < teste.in
The redirection operator '<' is not supported yet.
At line:1 char:24
+ ruby redir-entrada.rb < <<<< teste.in

No entanto, tem algumas outras saídas para conseguir fazer isso no Powershell. A primeira, é fazer pelo CMD:

cmd /c ruby programa.rb < teste.in

Simples. Mas feio. A outra, segundo informações do próprio Jeffrey Snover, é ler o arquivo com um cat (também conhecido como get-content) e passar por um pipe para a linha de comando do outro programa:

Sr.Canto@VMACHINE Ruby# cat teste.in -Encoding utf8 | ruby redir-entrada.rb
VINíCIUS
TESTE
TESTE_COM_NUMEROS_243523452435
áéíóúçãOI:ü'áà

Legal né? Notem que o exemplo acima já tem é a execução do programa e que eu precisei fazer ainda algumas coisas para funcionar:

  • Adicionar o parâmetro -encoding ao comando get-content. Isso permite ler o arquivo de entrada, em qualquer codificação que ele esteja. No meu caso, forcei o meu editor de textos a salvar em UTF8... e portanto, preciso dizer ao Powershell como abrir para não gerar acentos errados. Normalmente, isso não vai ser necessário. 
  • Usar a linha abaixo, que altera a codificação da saída do console:
    $outputencoding = [console]::outputencoding
    Isso fez com que os acentos "entrassem" corretamente para o interpretador do Ruby. Mais info aqui, no blog oficial.

Imagine agora que você tem vários arquivos de entrada, precisa testar todos e colocar em arquivos diferentes de saída, em outra pasta. Veja como resolver com poucas linhas:

ls input
| where {$_.extension -eq '.in'}
| foreach {
cat $_.fullname -Encoding utf8
| ruby redir-entrada.rb > $("output\$_.out")
}

Veja, em passos:

  • listar o conteúdo da pasta input.
  • pegar somente os arquivos com extensão .in
  • para cada um deles, fazer o seguinte
    • ler o arquivo e colocar o conteúdo no "pipeline"
    • executar o programa, nesse caso, em Ruby
    • redirecionar a saída com > para um arquivo diferente, nesse caso, vai ser o nome do arquivo mesmo com um .out no final e em outra pasta

Detalhe: tive que usar a propriedade fullname no comando cat para que o cat procure o arquivo na pasta certa.

Agora sim, resolvido o problema. Todos os testes da pasta input executados e as saídas, na pasta output. E documentado. Agradecimentos especiais ao Marcelo, quem precisou disso e de quebra aprendeu sobre Powershell, e ao Jeffrey Snover, que deu a resposta e mais ânimo para continuar lendo sobre o assunto.

Até mais! Nos próximos posts vou lembrar de como fazer algumas coisas legais em VBScript e JScript.

Categorias dessa postagem:

Comentários