Como posso canalizar e exibir a saída na linha de comando do Windows?

4

Eu tenho um processo que preciso executar em um arquivo de lote. Este processo produz alguma saída. Eu preciso mostrar tanto esta saída para a tela e enviar (canalizar) para outro programa.

O método bash usa tee :

echo 'ee' | tee /dev/tty | foo

Existe um equivalente para o Windows? Fico feliz em usar o PowerShell, se necessário.

Existem tee portas para o Windows, mas parece não haver um equivalente para /dev/tty , o que complica as coisas.

O caso de uso específico aqui: Eu tenho um programa (launch4j) que preciso executar, exibindo a saída para o usuário. Ao mesmo tempo, preciso ser capaz de detectar sucesso ou falha no script. Infelizmente, este programa não define um código de saída e não posso forçá-lo a fazê-lo. Minha solução atual envolve canalizar para find , para pesquisar a saída ( launch4j config.xml | find "Successfully created" ) - no entanto, isso engole a saída que preciso exibir. Portanto, eu preciso de alguma maneira para exibir tanto para a tela e enviar a saída para um comando - e este comando deve ser capaz de definir ERRORLEVEL (não pode ser executado de forma assíncrona). Isso será usado em um script de construção, que pode ser executado em muitas máquinas diferentes.

Para este caso específico, é necessário algo leve - não consigo instalar estruturas ou intérpretes adicionais (por exemplo, perl como sugerido em esta resposta ). Além disso, qualquer programa comercial deve ter uma licença que permita a redistribuição.

    
por Bob 12.06.2014 / 03:38

6 respostas

1

Você poderia tentar compilar este código e usá-lo como: echo something | mytee | foo .
Não sei se funcionará, pois não sei como o Windows lida com stderr / stdout , mas pode funcionar.

#include <stdio.h>
int main()
{
    int c;
    while((c = fgetc(stdin)) != EOF)
    {
        printf("%c", c);
        fprintf(stderr, "%c", c);
    }
    return 0;
}
    
por 12.06.2014 / 04:19
1

Uma maneira um pouco complicada de pensar é usar um dos programas tee portados, salvar em um arquivo temporário e testar o arquivo com find . No entanto, o uso de um arquivo temporário pode ser indesejável.

Se o PowerShell for uma opção, ele realmente terá um cmdlet Tee-Output . Não é tão direto quanto o exemplo bash, mas tem uma opção -Variable para salvar a saída em uma variável, que pode então ser pesquisada:

# save result in $LastOutput and also display it to the console
echo "some text" | Tee-Output -Variable LastOutput

# search $LastOutput for a pattern, using Select-String
# instead of find to keep it within PowerShell
$Result = $LastOutput | Select-String -Quiet "text to find"

# $Result should contain either true or false now
# this is the equivalent of batch "if errorlevel 1"
if ($Result -eq $True) {
    # the string exists in the output
}

Para responder à pergunta mais geral, também é possível canalizar a variável para qualquer outro programa, que irá então definir $LastExitCode . Como um one-liner que pode ser chamado a partir da linha de comando básica: powershell -c "echo text | Tee-Object -Variable Result; $Result | foo"

    
por 12.06.2014 / 03:38
1

Por que não apenas executar o comando no PowerShell usando Invoke-Command e capturar os resultados em uma variável. Você procura a variável por seus resultados, se eles estiverem lá, faça algo e exiba toda a saída para o console.

O arquivo de teste para capturar a saída é apenas o bloco de notas com o seguinte texto (C; \ Temp \ OutputTest.txt):

blahlbalsdfh
abalkshdiohf32iosknfsda
afjifwj93f2ji23fnsfaijfafds
fwjifej9f023f90f3nisfadlfasd
fwjf9e2902fjf3jifdsfajofsda
jfioewjf0990f
Successfully Created
fsjfd9waf09jf329j0f3wjf90awfjw0afwua9

No seu caso, você chamaria seu comando de algo como {& "Launch4j" config.xml} , mas pelo meu exemplo:

Invoke-Command -ScriptBlock {Get-Content C:\temp\OutputTest.txt} | foreach {
$_;
if ($_ -match "successfully created") {$flag = $true}
}
if ($flag) {
"do whatever"
}
    
por 12.06.2014 / 16:33
0

Eu recomendaria o TCC / LE do JP Software : ele implementa muitos dos recursos do bash , incluindo TEE , na sintaxe compatível com CMD. No seu exemplo, seria:

echo ee|tee con:|foo

Eu testei com o seguinte comando

for /l %n in (1,1,10) do ( echo %n %+ delay)|tee con:|nl.

Aqui NL é um programa que fornece uma listagem numerada, e a saída foi intercalada com linhas numeradas e não numeradas. O atraso de 1 segundo me permitiu ver que tanto o console quanto o leitor de tubo estavam recebendo linhas simultaneamente.

A versão LE é gratuita para uso privado.

    
por 12.06.2014 / 04:19
0

Você pode reescrever seu arquivo em lote como um script do PowerShell. O PowerShell tem Tee-Object (alias como Tee ).

Parameter Set: File Tee-Object [-FilePath] [-Append] [-InputObject ] [ ]

Parameter Set: LiteralFile Tee-Object -LiteralPath [-InputObject ] [ ]

Parameter Set: Variable Tee-Object -Variable [-InputObject ] [ ]

    
por 12.06.2014 / 14:31
-1

Basta colocar isso em um arquivo em lote (digamos echox.bat ):

@echo off
echo %1
echo %1|%2

Em seguida, chame esse lote assim:

echox 'c:\' dir

Ele imprimirá c:\ e imprimirá a saída de dir c:\ .

OBSERVAÇÃO: como estamos usando %1 , %2 , os parâmetros devem ser passados sem espaços ou dentro de " " e ' ' .

    
por 01.08.2014 / 22:48