Salida de tubería de comando línea por línea en Windows

2

Estoy ejecutando un servidor desde un archivo por lotes y quiero que la salida del servidor se muestre en la pantalla y también se escriba en un archivo de registro. Encontré una manera de hacer esto a partir de esta respuesta :

powershell "startmyserver | tee server.log"

El problema es que la tubería hace que el primer comando se ejecute y se complete por completo antes de que se ejecute el segundo comando. Esto significa que no puedo monitorear la salida estándar de mi servidor mientras se está ejecutando, que es lo que estoy tratando de hacer (no quiero tener que apagar el servidor solo para verificar los mensajes de registro más recientes).

Para un ejemplo más simple lo intenté pause. Bueno, pauseno existe en Powershell, así que tuve que ejecutarlo dentro de un cmdshell anidado :

powershell "cmd /c pause | tee test.txt"

Como era de esperar, después de ejecutar este comando me sale un cursor intermitente. Después de un tiempo, presiono una tecla y luego aparece "Presione cualquier tecla para continuar" y se escribe en el archivo casi al mismo tiempo.

Lo que quiero que suceda es la tubería para transmitir el stdout línea por línea al siguiente comando. En otras palabras, cada vez que se encuentra con un carácter EOL, debe enviar algún resultado y esto (en mi caso tee) debería hacer que el texto aparezca en la pantalla y se escriba simultáneamente en el archivo. (De hecho, incluso no me preocupa si el texto se escribe en el archivo línea por línea, podría escribirse todo al final, aunque eso no sería lo ideal. Solo quiero poder ver las líneas en la pantalla tal como están escritas).

¿Es esto posible en Símbolo del sistema y / o Powershell?

Kidburla
fuente
@PimpJuiceIT Creo que sí importa con las posiciones de comillas dobles. Si corres, powershell cmd /c pause | tee "test.txt"estás corriendo tee en tu contexto actual. Estoy ejecutando esto desde cmd (no ps1), por lo que este comando fallará al igual teeque un comando Powershell. si este comando funcionó para usted, supongo que (a) tiene otro teeen su sistema o (b) lo ejecutó desde Powershell. Ninguno de los cuales es mi caso de uso.
Kidburla
@PimpJuiceIT ¿tiene otro ejemplo de un comando que podría usar en lugar de pause? Utilicé pausesolo por conveniencia porque no quería un comando que terminara de inmediato y, por lo tanto, hiciera imposible saber si las líneas se transmitieron antes de que se completara el comando
Kidburla
Tal vez duerma tal vez, pero parece que encontró una solución que funciona, así que ahora todo es discutible.
Pimp Juice IT

Respuestas:

1

Este problema se explica en Stack Overflow como el hecho de que PowerShell Tee-Objectno vacía la secuencia de salida, sino que solo espera a que la fuente lo haga, por lo que obtiene la salida al final de la operación. Esto es por diseño.

La solución propuesta en la respuesta fue usar este código:

./program | ForEach-Object {
    Write-Host $_
    $_
} | Set-Content program.log

Una formulación alternativa para probar si la anterior no funcionó es:

./program | ForEach-Object {
    [Console]::WriteLine($_)
    [Console]::Out.Flush()
    $_
} | Set-Content program.log

Entonces el comando se vería así:

PowerShell -ExecutionPolicy Unrestricted "startmyserver | ForEach-Object { Write-Host $_; $_} | Set-Content server.log"

En mis modestas pruebas, la salida se generó demasiado rápido para ver si esto funcionó como usted especificó.

harrymc
fuente
¡Gracias! ¿Tiene alguna idea de cómo (a) hacer que esto escriba stdout y stderr, (b) adjuntar a un archivo que ya existe en lugar de crear uno nuevo?
Kidburla
1
Ver este post .
harrymc
Gracias, y me las arreglé para resolver la parte (b) utilizando Add-Contenten lugar deSet-Content
Kidburla