¿Cómo puedo usar la magia BASH para lograr esto?
Solo quiero ver la salida de stderr en la pantalla,
pero quiero que tanto stdout como stderr se escriban en un archivo.
Aclaración: Quiero que stdout y stderr terminen en el mismo archivo. En el orden en que suceden.
Lamentablemente, ninguna de las respuestas a continuación hace esto.
bash
shell
io-redirection
Andreas
fuente
fuente
Respuestas:
Incluso sin ninguna redirección, o con nada más
>logfile 2>&1
, no se garantiza que vea la salida en orden de generación.Para empezar, el stdout de la aplicación tendrá un buffer de línea (a tty) o un buffer (a una tubería) pero stderr no tiene buffer, por lo que las relaciones entre el orden de salida se rompen en lo que respecta al lector. Las etapas posteriores en cualquier canalización que pueda inventar no obtendrán un acceso ordenado de manera determinista a las dos corrientes (son conceptualmente cosas que suceden en paralelo, y siempre está sujeto al planificador, si para el momento en que su lector obtiene una porción, el escritor ya tiene escrito en ambas tuberías, no se puede saber cuál vino primero).
"[L] a orden de que sucedan" solo es realmente conocido por la aplicación. El pedido de salida a través de stdout / stderr es un problema bien conocido, quizás clásico.
fuente
Cuando utiliza la construcción:
1>stdout.log 2>&1
tanto stderr como stdout se redirigen al archivo porque la redirección stdout se configura antes de la redirección stderr .Si invierte el orden, puede obtener stdout redirigido a un archivo y luego copiar stderr a stdout para que pueda canalizarlo
tee
.fuente
tee -a
con el mismo archivo usado1>
para sumar ambas salidas en el mismo archivo. Algo así como:./test 2>&1 1>out+err.log | tee -a out+err.log
wget -O - www.google.de
para mí. (compárese con la solución a continuación)tee -a
no funcionará de manera confiable para tener el mismo resultado que estaría en la consola si no se redirige nada. La salida que se realizatee
puede retrasarse ligeramente en comparación con la salida que proviene directamente del comando, por lo que puede aparecer más adelante en el registro.He podido lograr esto colocando la siguiente línea en la parte superior de un script bash:
Esto redirigirá stdout al archivo
log
(1>>log
), luego tee stderr al archivolog
(2> >(tee -a log
) y lo dirigirá de nuevo a stderr (>&2)
. De esta manera, obtengo un solo archivolog
, que muestra tanto stdout como stderr en orden, y stderr también es se muestra en la pantalla como de costumbre.El problema es que solo parece funcionar cuando anexo el archivo. Si no agrego, parece que las dos redirecciones se golpean entre sí, y solo obtengo la última salida.
fuente
Desea duplicar la secuencia de error para que aparezca tanto en la consola como en el archivo de registro. La herramienta para eso es
tee
, y todo lo que necesita hacer es aplicarlo a la secuencia de error. Desafortunadamente, no hay una construcción de shell estándar para canalizar el flujo de error de un comando en otro comando, por lo que se requiere una pequeña reorganización del descriptor de archivo.fuente
tee
introduce un retraso aquí. No creo que haya una solución de shell pura. De hecho, me pregunto si hay una solución sin modificar la aplicación de alguna manera.Para escribir stderr en la pantalla y escribir AMBOS stderr y stdout en un archivo, Y que las líneas para stderr y stdout salgan en la misma secuencia que lo harían si ambas se escribieran en la pantalla:
Resulta ser un problema difícil, especialmente la parte de tener "la misma secuencia" que esperaría si simplemente los escribiera en la pantalla. En términos simples: escriba cada uno en su propio archivo, haga un poco de magia de proceso en segundo plano para marcar cada línea (en cada archivo) con la hora exacta en que se produjo la línea, y luego: "seguir - seguir" el archivo stderr en la pantalla , pero para ver AMBOS "stderr" y "stdout" juntos, en secuencia, clasifique los dos archivos (con marcas de tiempo exacto en cada línea) juntos.
Código:
Sí, esto parece elaborado, y da como resultado 4 archivos de salida (2 de los cuales puede eliminar). Parece que este es un problema difícil de resolver, por lo que tomó varios mecanismos.
Al final, para ver los resultados de AMBOS stdout y stderr en la secuencia que esperarías, ejecuta esto:
La única razón por la que la secuencia es al menos muy cercana a lo que hubiera sido que stdout y stderr simplemente hubieran ido a la pantalla es: Cada línea está marcada con una marca de tiempo hasta el milisegundo.
Para ver stderr en la pantalla a medida que avanza el proceso, use esto:
Espero que ayude a alguien, que llegó aquí mucho después de que se hizo la pregunta original.
fuente
Deje
f
ser el comando que desea ejecutar, entonces estodebería darte lo que deseas. Por ejemplo,
wget -O - www.google.de
se vería así:fuente
Dado lo que he leído aquí, la única solución que puedo ver sería anteponer cada línea, ya sea STOUT o STERR con un intervalo de tiempo / marca de tiempo. date +% s llegaría a segundos, pero eso es lento para mantener el orden. Además, el registro de alguna manera tendría que ser ordenado. Más trabajo del que soy capaz.
fuente
He luchado con este requisito exacto, y al final no pude encontrar una solución simple. Lo que terminé haciendo en su lugar fue esto:
Agrega stdout y stderr, en el orden intercalado adecuado, al archivo de registro. Y si se produce algún error (según lo determine el estado de salida del comando), envía toda la salida (stdout y stderr) a stdout, nuevamente en el orden correcto intercalado. Encontré que esto es un compromiso razonable para mis necesidades. Si desea un archivo de registro de una sola ejecución en lugar de un archivo de varias ejecuciones en crecimiento, es aún más simple:
fuente
stderr a comando sustituido
tee -a
, y stdout anexando al mismo archivo:y nota: también asegúrese de ordenar correctamente (pero sin stderr-show) hay un comando 'unbuffer' de las herramientas 'esperar', que simula tty y mantiene stdout / err en orden como se mostraría en la terminal:
fuente