¿Cómo hago eco y envío la salida de la consola a un archivo en un script bat?

136

Tengo un script por lotes que ejecuta una tarea y envía la salida a un archivo de texto. ¿Hay alguna manera de que la salida se muestre también en la ventana de la consola?

Por ejemplo:

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

¿Hay alguna manera de tener la salida de dirvisualización en la ventana de la consola y ponerla en el archivo de texto?

JamesEggers
fuente
Aquí se explican las redirecciones que puede hacer, y algunos ejemplos. <br> Espero que ayude :)
emoSTN
Tenga en cuenta, @Vadzim, que una pregunta formulada el 2 de febrero de 2009 a las 16:38 no puede considerarse un duplicado de una pregunta formulada casi tres meses después, el 28 de abril de 2009 a las 06:32.
Compo

Respuestas:

216

No, no puedes con la redirección pura.
Pero con algunos trucos (como tee.bat ) puedes.

Intento explicar un poco la redirección.

Redirige una de las diez secuencias con > archivo o <archivo
No es importante, si la redirección es anterior o posterior al comando, por lo que estas dos líneas son casi iguales.

dir > file.txt
> file.txt dir

La redirección en este ejemplo es solo un acceso directo para 1> , esto significa que la secuencia 1 (STDOUT) será redirigida.
Por lo tanto, puede redirigir cualquier secuencia con anteponer el número como 2> err.txt y también se le permite redirigir múltiples secuencias en una línea.

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

En este ejemplo, la "salida estándar" irá a files.txt, todos los errores estarán en err.txt y el stream3 irá a nothing.txt (DIR no usa el stream 3).
Stream0 es STDIN
Stream1 es STDOUT
Stream2 es STDERR
Stream3-9 no se utilizan

Pero, ¿qué sucede si intentas redirigir la misma secuencia varias veces?

dir > files.txt > two.txt

"Solo puede haber uno", ¡y siempre es el último!
Entonces es igual a dir> two.txt

Ok, hay una posibilidad adicional, redirigir una transmisión a otra transmisión.

dir 1>files.txt 2>&1 

2> & 1 redirige stream2 a stream1 y 1> files.txt redirige todo a files.txt .
¡El orden es importante aquí!

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

son diferentes. El primero redirige todo (STDOUT y STDERR) a NUL,
pero la segunda línea redirige el STDOUT a NUL y STDERR al STDOUT "vacío".

Como conclusión, es obvio por qué los ejemplos de Otávio Décio y andynormancx no pueden funcionar.

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

Ambos intentan redirigir stream1 dos veces, pero "Solo puede haber uno", y siempre es el último.
Entonces obtienes

command 1>&1
dir 1>&2

Y en la primera muestra, la redirección de stream1 a stream1 no está permitida (y no es muy útil).

Espero eso ayude.

jeb
fuente
24
Por lo tanto, es imposible con el shell de Windows nativo
fantastory
77
@fantastory Es posible, vea esta gran solución del lote
jeb
97
No puedo creer que acabo de leer esta publicación completa para descubrir que todo se puede resumir como "No".
Charles McKelvey
1
¿Qué pasa con el segundo mecanismo "manejar la duplicación"? Experimenté con 3<&2(tenga en cuenta el LT en lugar de GT), y luego 3>errors.txt. Pero esto terminó mal: toda la salida posterior de stderr se capturó en errors.txt(es decir, ¡desde otros comandos también!).
Tomasz Gandor
for /f "delims=" %%v in ('dir') do echo %%v>>file.txtAunque podrías usarlo .
scriptmastere02
32

Simplemente use la versión de Windows del comando tee de UNIX (que se encuentra en http://unxutils.sourceforge.net ) de esta manera:

mycommand > tee outpu_file.txt

Si también necesita la salida STDERR, utilice lo siguiente.
El 2>&1combina la salida STDERR en STDOUT (la corriente primaria).

mycommand 2>&1 | tee output_file.txt
atn
fuente
3
El PowerShell Tee-Object ofrece una funcionalidad similar. Get-Process | Tee-Object -file c: \ scripts \ test.txt
Kevin Obee
Intenté esto tanto en PowerShell como en el shell normal. 1>tee a.txtredirigirá stdout a un archivo llamado en teelugar de llamar al teecomando. ¿Alguien puede confirmar que esta respuesta les funciona?
mafu
@mafu, puedo confirmar esto.
Cerno
@mafu La respuesta anterior es ligeramente incorect. Tienes que usar la tubería "|" en lugar del ">" en el ejemplo superior. Extrañamente, el orden de la salida STDOUT y STDERR se mezcló en la línea de comando en ese caso. Sin embargo, el ejemplo inferior funciona perfectamente para mí.
Cerno
Además, la descarga de sourceforge estaba rota para mí. Encontré un host alternativo aquí: wzw.tum.de/public-html/syring/win32/UnxUtilsDist.html (Universidad de Munich)
Cerno
9

Si no necesita la salida en tiempo real (es decir, como el programa lo está escribiendo), puede agregar

type windows-dir.txt

despues de esa linea.

Mark Pim
fuente
o en la misma línea (útil en el símbolo): dir > windows-dir.txt & type windows-dir.txt. Esto también se aplica a los bloques: ( echo %date% <NL> echo %username% <NL> echo %time% <NL> pause>CON )>test.txt & type test.txt. Sin embargo, si se requiere que la salida en tiempo real, se puede utilizar por ejemplo un puerto de las ventanas de la camiseta herramienta para eso ...
mousio
7

La solución que funcionó para mí fue: dir> a.txt | escriba a.txt .

NSPKUWCExi2pr8wVoGNk
fuente
2
Esto funciona con comandos con bajo rendimiento. Con el comando de salida grande no funciona porque muestra solo el primer búfer. Él está pidiendo una salida en tiempo real mientras guarda la salida en un archivo de registro.
NetVicious
Sería problemático si usa >> en lugar de>
Nime Cloud
6

Sí, hay una manera de mostrar una salida de comando único en la consola (pantalla) y en un archivo. Usando su ejemplo, use ...

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

Explicación detallada:

El FORcomando analiza la salida de un comando o texto en una variable, a la que se puede hacer referencia varias veces.

Para un comando, como DIR /B, encerrar entre comillas simples como se muestra en el ejemplo a continuación. Reemplace el DIR /Btexto con su comando deseado.

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

Para mostrar texto, encierre el texto entre comillas dobles como se muestra en el ejemplo a continuación.

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

... Y con envoltura de línea ...

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

Si tiene momentos en los que desea la salida solo en la consola (pantalla), y otros tiempos enviados solo al archivo, y otros tiempos enviados a ambos, especifique la cláusula "DO" del bucle FOR utilizando una variable, como se muestra a continuación con %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
Amazinate
fuente
Deberías usar delims=en su lugar.
scriptmastere02
3
command > file >&1
Otávio Décio
fuente
Es más rápido cuando no escribe los datos en la pantalla, ya que no llena el búfer con basura, sino que le permite ejecutar el trabajo por lotes. si está depurando, no usaría la sintaxis del archivo.
Desarrollador aleatorio
@andynormancx sí olvidó escribir eso en lugar de cortar y pegar desde el CMD.
Desarrollador aleatorio
No pude hacer que la sintaxis funcione bajo un símbolo del sistema de Windows y en su lugar he seguido el comando de tipo.
JamesEggers
& 2 funciona, sin embargo, el archivo ahora no se está creando cuando lo pruebo.
JamesEggers
55
si hago "dir> file.txt> & 2" file.txt no se está creando. La salida del directorio se repite en la consola pero no se crea el archivo. El archivo se crea cuando "> & 2" no está presente.
JamesEggers
2

Si desea agregar en lugar de reemplazar el archivo de salida, puede usar

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

o

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

Mi opción fue esta:

Cree una subrutina que tome el mensaje y automatice el proceso de enviarlo a la consola y al archivo de registro.

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

Si agrega una variable al mensaje, asegúrese de eliminar las comillas antes de enviarlo a la subrutina o puede arruinar su lote. Por supuesto, esto solo funciona para hacer eco.

JPZ
fuente
¡GUAU SÍ! ¡¡Realmente me gusta esto!! Sin embargo, hice tres cambios, espero que les gusten. 1) Utilizo en setlocal enabledelayedexpansionlugar de solo setlocal 2) Utilizo la expansión retrasada para la variable del archivo de registro, por lo que en >> !logfile!lugar de >> %logfile%dentro de la subrutina. De esta manera, funciona cuando se llama desde un bloque de código (como dentro de una instrucción if). 3) Eliminé la línea "establecer mensaje" porque no hay necesidad de la variable adicional. Ya lo tenemos, $~1así que tengo echo $~1para ambos comandos echo.
Nate
2

Hice una consola C # simple que puede manejar la salida en tiempo real a la pantalla cmd y al registro

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;
    }
}

El uso del archivo por lotes es el mismo que el de Unix. tee

foo | tee xxx.log

Y aquí está el repositorio que incluye Tee.exe en caso de que no tenga una herramienta para compilar https://github.com/iamshiao/Tee

Circle Hsiao
fuente
0

La solución proporcionada por "Tomas R" funciona perfectamente para la pregunta del OP y está disponible de forma nativa.

Pruebe: chkdsk c:> output.txt | escriba output.txt

El resultado de este comando implica un porcentaje de finalización que se genera en serie en el archivo, por lo que se verá un poco desordenado (es decir, el texto se agregará a medida que avance). Esto no sucede con los bits que salen a STDOUT (la pantalla). Es lo que sería si solo hicieras el mismo comando sin redireccionar.

J0N
fuente
-3

Creo que quieres algo en este sentido:

echo Your Msg> YourTxtFile.txt

O si quieres una nueva línea:

echo Your Msg>> YourTxtFile.txt

Estos comandos son excelentes para los registros.

Nota: Esto algunas veces fallará y reemplazará el archivo de texto completo en mi computadora.

Otra nota: si el archivo no existe, creará el archivo.

Gladius125
fuente
1
no, OP quería tener la salida en un archivo y en la pantalla. El suyo solo escribe en el archivo. (Y >está diseñado para sobrescribir el archivo. Úselo >>para agregar )
Stephan