Cómo guardar stdout en un archivo, stderr en un archivo, stdout+stderr en un archivo y obtener stdout + stderr en la terminal como es normal para un script de shell

Cómo guardar stdout en un archivo, stderr en un archivo, stdout+stderr en un archivo y obtener stdout + stderr en la terminal como es normal para un script de shell

¿Cómo puedo guardar stdout en un archivo, stderr en otro archivo, stdout+stderr en un tercer archivo y también obtener stdout + stderr en la terminal como es normal para un script de shell?

Encontré esto en otro lugar:

exec > >(tee std_out) 2> >(tee err_out >&2)
ls # Should got to std_out
fsdfs # Command not found goes to err_out

Lo cual está muy cerca. Si lo ejecuto bash test.sh 2>&1 | tee output, funciona, pero no tengo acceso a cómo se ejecuta mi script. Es un sistema cicd. Necesito poder hacer la "salida combinada" desde dentro del script usando exec.

Estoy creando una biblioteca de CI/CD y no puedo saber para qué usarían la biblioteca los clientes, por lo que quiero tener en cuenta cada caso de uso.

Respuesta1

Simplemente ampliando su enfoque:

exec 2> >(tee -a stderr stdall) 1> >(tee -a stdout stdall)

El error estándar se escribirá en el archivo denominado stderr, la salida estándar stdouty tanto el error estándar como la salida estándar también se escribirán en la consola (o lo que sea que apunten los dos descriptores de archivo en el momento de execla ejecución) y en stdall.
tee -a(añadir) es necesario para evitar stdallque se sobrescriba en el segundo teeque comienza a escribir en él.

Tenga en cuenta queel ordenen el que se realizan las redirecciones es relevante: la sustitución del segundo proceso se ve afectada por la primera redirección, es decir, los errores que emitió se enviarían a >(tee -a stderr stdall). Por supuesto, puede redirigir el error estándar de sustitución del segundo proceso para /dev/nullevitar este efecto secundario. Redirigir la salida estándar antes del error estándar enviaría todos los errores a stdouty stdalltambién.

Dado que los comandos en las sustituciones de procesos de Bash se ejecutanasincrónicamente, no hay forma de garantizar que su salida se muestre en el orden en que se generó. Peor aún, es probable que fragmentos de la salida estándar y del error estándar acaben apareciendo en la misma línea.

Respuesta2

Su script puede ejecutarse automáticamente $0(configurando y verificando una variable de entorno para evitar la recursividad infinita) en lugar de depender de > >(...)la construcción de bash, que IMLE es caprichosa y poco confiable.

if [ "$REDIRECTED" != 1 ]; then
        export REDIRECTED=1
        set -o pipefail
        { { "$0" | tee stdout >&3; } 2>&1 | tee stderr; } 3>&1 | tee stdboth
        exit
fi
# rest of your script here

Dado que teeno utiliza buffering de líneas (ni se podría forzar a hacerlo con stdbuf(1)), el orden de los datos escritos en stdout y stderr no se respetará en la salida final. Con un comando que utiliza almacenamiento en búfer completo y escribe tanto en stdout como en stderr, ni siquiera un almacenamiento en búfer de línea teeayudará y, peor aún, puede obtener líneas de salida que son mitad stdout y mitad stderr.

No creo que haya ninguna solución para eso usando sólo el lenguaje de shell y las utilidades de línea de comandos disponibles.

Respuesta3

Estoy creando una biblioteca de CI/CD y no puedo saber para qué usarían la biblioteca los clientes, por lo que quiero tener en cuenta cada caso de uso.

Cuestiono la necesidad de bash para procesar los resultados, dado que este es el escenario. Idealmente, en este contexto, desearía poner una marca de tiempo en la salida y darle una identificación para el tipo de salida estándar y que la aplicación sea la que decida qué hacer con los mensajes.

información relacionada