Como ecoar e enviar a saída do console para um arquivo em um script bat?


136

Eu tenho um script em lote que executa uma tarefa e envia a saída para um arquivo de texto. Existe uma maneira de exibir a saída na janela do console também?

Por exemplo:

c:\Windows>dir > windows-dir.txt

Existe uma maneira de direxibir a saída na janela do console e colocá-la no arquivo de texto?


Aqui são explicados os redirecionamentos que você pode fazer, e alguns exemplos <br> Espero que ajude :).
emoSTN


@Vadzim, observe que uma pergunta feita em 2 de fevereiro de 2009 às 16:38 não pode ser considerada uma duplicata de uma pergunta feita quase três meses depois em 28 de abril de 2009 às 06:32.
Compo

Respostas:


216

Não, você não pode com o redirecionamento puro.
Mas com alguns truques (como tee.bat ) você pode.

Eu tento explicar um pouco o redirecionamento.

Você redireciona um dos dez fluxos com arquivo> ou <arquivo
Não é importante, se o redirecionamento for anterior ou posterior ao comando, portanto, essas duas linhas são praticamente as mesmas.

dir > file.txt
> file.txt dir

O redirecionamento neste exemplo é apenas um atalho para 1> , isso significa que o fluxo 1 (STDOUT) será redirecionado.
Assim, você pode redirecionar qualquer fluxo acrescentando o número como 2> err.txt e também é permitido redirecionar vários fluxos em uma linha.

dir 1> files.txt 2> err.txt 3> nothing.txt

Neste exemplo, a "saída padrão" entrará em files.txt, todos os erros estarão em err.txt e o stream3 entrará em nothing.txt (o DIR não usa o stream 3).
Stream0 é STDIN
Stream1 é STDOUT
Stream2 é
STDERR Stream3-9 não são usados

Mas o que acontece se você tentar redirecionar o mesmo fluxo várias vezes?

dir > files.txt > two.txt

"Só pode haver um", e é sempre o último!
Portanto, é igual a dir> two.txt

Ok, há uma possibilidade extra, redirecionando um fluxo para outro fluxo.

dir 1>files.txt 2>&1 

2> & 1 redireciona stream2 para stream1 e 1> files.txt redireciona tudo para files.txt .
A ordem é importante aqui!

dir ... 1>nul 2>&1
dir ... 2>&1 1>nul

são diferentes. O primeiro redireciona tudo (STDOUT e STDERR) para NUL,
mas a segunda linha redireciona o STDOUT para NUL e STDERR para o STDOUT "vazio".

Como conclusão, é óbvio que os exemplos de Otávio Décio e andynormancx não podem funcionar.

command > file >&1
dir > file.txt >&2

Ambos tentam redirecionar o stream1 duas vezes, mas "Só pode haver um", e é sempre o último.
Então você recebe

command 1>&1
dir 1>&2

E, na primeira amostra, o redirecionamento do fluxo1 para o fluxo1 não é permitido (e não é muito útil).

Espero que ajude.


24
Por isso, é impossível com janelas nativas desembolsar
fantastory

7
@fantastory É possível, ver este grande solução de dbenham lote do Windows: 'tee' comando
jeb

97
Não acredito que acabei de ler este post inteiro para descobrir que tudo pode ser resumido como "Não".
Charles McKelvey

1
E o segundo mecanismo "manipular duplicação"? Eu experimentei 3<&2(observe o LT em vez de GT) e, em seguida 3>errors.txt. Mas isso terminou mal - toda a saída subseqüente do stderr foi capturada para errors.txt(ou seja, de outros comandos também!).
Tomasz Gandor

Você poderia usar for /f "delims=" %%v in ('dir') do echo %%v>>file.txtembora.
precisa

32

Basta usar a versão do Windows do comando tee do UNIX (encontrado em http://unxutils.sourceforge.net ) desta maneira:

mycommand > tee outpu_file.txt

Se você também precisar da saída STDERR, use o seguinte.
O 2>&1combina a saída STDERR em STDOUT (o fluxo primário).

mycommand 2>&1 | tee output_file.txt

3
O PowerShell Tee-Object oferece funcionalidade semelhante. Get-Process | Tee-Object -file c: \ Scripts \ test.txt
Kevin Obee

Eu tentei isso no PowerShell e no shell regular. 1>tee a.txtredirecionará stdout para um arquivo chamado em teevez de chamar o teecomando. Alguém pode confirmar que essa resposta funciona para eles?
mafu 11/01/19

@mafu Eu posso confirmar isso.
Cerno 10/02

@mafu A resposta acima é um pouco incorreta. Você tem que usar o pipe "|" em vez de ">" no exemplo superior. Estranhamente, a ordem das saídas STDOUT e STDERR foi misturada na linha de comando nesse caso. O exemplo inferior funciona perfeitamente para mim.
Cerno

Além disso, o download do sourceforge foi interrompido para mim. Encontrei um host alternativo aqui: wzw.tum.de/public-html/syring/win32/UnxUtilsDist.html (Universidade de Munique)
Cerno

9

Se você não precisa da saída em tempo real (ou seja, enquanto o programa está gravando), você pode adicionar

type windows-dir.txt

depois dessa linha.


ou na mesma linha (útil na linha de comando): dir > windows-dir.txt & type windows-dir.txt. Isto também se aplica aos blocos: ( echo %date% <NL> echo %username% <NL> echo %time% <NL> pause>CON )>test.txt & type test.txt. No entanto, se a saída é necessária em tempo real, você pode usar por exemplo uma janela da porta do tee ferramenta para isso ...
mousio

7

A solução que funcionou para mim foi: dir> a.txt | digite a.txt .


2
Isso funciona com comando com baixa saída. Com comando de saída grande, não funciona porque mostra apenas o primeiro buffer. Ele está solicitando uma saída em tempo real enquanto salva a saída em um arquivo de log.
NetVicious

Seria problemático se você usar >> em vez de> #
Nime Cloud

6

Sim, existe uma maneira de mostrar uma única saída de comando no console (tela) e em um arquivo. Usando seu exemplo, use ...

@ECHO OFF
FOR /F "tokens=*" %%I IN ('DIR') DO ECHO %%I & ECHO %%I>>windows-dir.txt

Explicação detalhada:

O FORcomando analisa a saída de um comando ou texto em uma variável, que pode ser referenciada várias vezes.

Para um comando, como DIR /B, coloque aspas simples, como mostrado no exemplo abaixo. Substitua o DIR /Btexto pelo comando desejado.

FOR /F "tokens=*" %%I IN ('DIR /B') DO ECHO %%I & ECHO %%I>>FILE.TXT

Para exibir texto, coloque o texto entre aspas duplas, como mostrado no exemplo abaixo.

FOR /F "tokens=*" %%I IN ("Find this text on console (screen) and in file") DO ECHO %%I & ECHO %%I>>FILE.TXT

... E com quebra de linha ...

FOR /F "tokens=*" %%I IN ("Find this text on console (screen) and in file") DO (
  ECHO %%I & ECHO %%I>>FILE.TXT
)

Se houver momentos em que você deseja a saída apenas no console (tela), e outros horários enviados apenas para o arquivo e outros horários enviados para ambos, especifique a cláusula "DO" do loop FOR usando uma variável, como mostrado abaixo em %TOECHOWHERE%.

@ECHO OFF
FOR %%I IN (TRUE FALSE) DO (
  FOR %%J IN (TRUE FALSE) DO (
    SET TOSCREEN=%%I & SET TOFILE=%%J & CALL :Runit)
)
GOTO :Finish

:Runit
  REM Both TOSCREEN and TOFILE get assigned a trailing space in the FOR loops
  REM above when the FOR loops are evaluating the first item in the list,
  REM "TRUE".  So, the first value of TOSCREEN is "TRUE " (with a trailing
  REM space), the second value is "FALSE" (no trailing or leading space).
  REM Adding the ": =" text after "TOSCREEN" tells the command processor to
  REM remove all spaces from the value in the "TOSCREEN" variable.
  IF "%TOSCREEN: =%"=="TRUE" (
      IF "%TOFILE: =%"=="TRUE" (
          SET TEXT=On screen, and in "FILE.TXT"
          SET TOECHOWHERE="ECHO %%I & ECHO %%I>>FILE.TXT"
        ) ELSE (
          SET TEXT=On screen, not in "FILE.TXT"
          SET TOECHOWHERE="ECHO %%I"
      )
    ) ELSE (
      IF "%TOFILE: =%"=="TRUE" (
          SET TEXT=Not on screen, but in "FILE.TXT"
          SET TOECHOWHERE="ECHO %%I>>FILE.txt"
        ) ELSE (
          SET TEXT=Not on screen, nor in "FILE.TXT"
          SET TOECHOWHERE="ECHO %%I>NUL"
      )
  )
  FOR /F "tokens=*" %%I IN ("%TEXT%") DO %TOECHOWHERE:~1,-1%
GOTO :eof

:Finish
  ECHO Finished [this text to console (screen) only].
  PAUSE

Você deve usar em seu delims=lugar.
precisa

3
command > file >&1

É mais rápido quando você não grava os dados na tela, pois não enche o buffer de porcaria, mas deixa que o trabalho em lote seja executado. se você estiver depurando, não usaria a sintaxe do arquivo.
Random Developer

@andynormancx yup esqueceu de digitar isso em vez de recortar e colar do CMD.
Random Developer

Não consegui que a sintaxe funcionasse em um prompt de comando do Windows e, em vez disso, segui o comando type.
JamesEggers 02/02/09

& 2 funciona, no entanto, o arquivo não está sendo criado quando eu o testo.
21119 JamesEggers

5
se eu fizer "dir> file.txt> & 2" file.txt não está sendo criado. A saída do diretório está sendo ecoada no console, mas o arquivo não está sendo criado. O arquivo é criado quando o "> & 2" não está presente.
2111 JamesEggers

2

Se você deseja anexar em vez de substituir o arquivo de saída, pode usar

dir 1>> files.txt 2>> err.txt

ou

dir 1>> files.txt 2>>&1

2

Minha opção foi esta:

Crie uma sub-rotina que receba a mensagem e automatize o processo de enviá-la ao console e ao arquivo de log.

setlocal
set logfile=logfile.log

call :screenandlog "%DATE% %TIME% This message goes to the screen and to the log"    

goto :eof

:screenandlog
set message=%~1
echo %message% & echo %message% >> %logfile%
exit /b

Se você adicionar uma variável à mensagem, remova as aspas nela antes de enviá-la para a sub-rotina ou poderá danificar seu lote. Claro que isso só funciona para ecoar.


WOW SIM! Eu realmente gosto disso!! Fiz três alterações, espero que você goste. 1) Eu uso em setlocal enabledelayedexpansionvez de apenas setlocal 2) Eu uso a expansão atrasada para a variável do arquivo de log, portanto, em >> !logfile!vez de >> %logfile%dentro da sub-rotina. Dessa forma, funciona quando chamado de dentro de um bloco de código (como dentro de uma instrução if). 3) Removai a linha "definir mensagem" porque não há necessidade da variável extra. Já o temos, $~1então tenho os echo $~1dois comandos de eco.
Nate

2

Eu criei um console C # simples que pode lidar com a saída em tempo real para a tela e o log do cmd

class Tee
{
    static int Main(string[] args)
    {
        try
        {
            string logFilePath = Path.GetFullPath(args[0]);

            using (StreamWriter writer = new StreamWriter(logFilePath, true))
            {
                for (int value; (value = Console.In.Read()) != -1;)
                {
                    var word = Char.ConvertFromUtf32(value);
                    Console.Write(word);
                    writer.Write(word);
                }
            }
        }
        catch (Exception)
        {
            return 1;
        }
        return 0;
    }
}

O uso do arquivo em lote é o mesmo de como você usa o Unix tee

foo | tee xxx.log

E aqui está o repositório que inclui o Tee.exe, caso você não tenha uma ferramenta para compilar https://github.com/iamshiao/Tee



0

A solução fornecida pelo "Tomas R" funciona perfeitamente para a pergunta do OP e está disponível nativamente.

Tente: chkdsk c:> output.txt | digite output.txt

A saída desse comando envolve uma porcentagem de conclusão que é enviada serialmente para o arquivo, portanto, ele ficará um pouco confuso (ou seja, o texto será anexado à medida que avança). Isso não acontece com os bits que são enviados para STDOUT (a tela). É como seria se você apenas executasse o mesmo comando sem redirecionar.


-3

Eu acho que você quer algo nesse sentido:

echo Your Msg> YourTxtFile.txt

Ou se você quiser uma nova linha:

echo Your Msg>> YourTxtFile.txt

Esses comandos são ótimos para logs.

Nota: Isso às vezes falha e substitui o arquivo de texto inteiro no meu computador.

Outra nota: Se o arquivo não existir, ele será criado.


1
não, o OP queria ter a saída em um arquivo e na tela. O seu apenas grava no arquivo. (E >foi projetado para substituir o arquivo. Use >>para anexar )
Stephan
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.