bash - tipos - ver el contenido de un archivo en linux
Escritura de salidas para archivo de registro y consola (9)
En shell Unix, tengo un archivo env (archivo env define los parámetros necesarios para ejecutar el script del usuario como nombre de archivo de registro y ruta, redirigir salidas y errores al archivo de registro, detalles de conexión de base de datos, etc. ) que redirige todas las salidas ( mensajes de eco ) y errores en el archivo de registro del script ejecutado utilizando el siguiente código:
exec 1>>${LOG_FILE}
exec 2>>${LOG_FILE}
El archivo env se ejecuta al comienzo de cada script. Debido al código anterior en el archivo env, todas las salidas de la consola que pueden ser salidas del usuario o errores se envían directamente al archivo de registro, que es lo que realmente necesitaba.
Pero hay algunas salidas de usuario selectivas que quiero que se muestren tanto en la consola como en el archivo de registro. Pero debido al código anterior, no puedo hacerlo.
Sé que si elimino el código anterior, puedo obtener el resultado deseado para este caso, pero tendré que escribir manualmente todas las demás salidas en el archivo de registro, lo cual no es una tarea fácil.
¿Hay alguna manera de obtener el resultado tanto en la consola como en el archivo de registro sin eliminar los códigos anteriores?
Encuentro muy útil agregar tanto stdout como stderr a un archivo de registro. Me alegré de ver una solución de alfonx con exec > >(tee -a)
, porque me preguntaba cómo lograr esto usando el exec
. Me encontré con una solución creativa que usa la sintaxis here-doc y .
: https://unix.stackexchange.com/questions/80707/how-to-output-text-to-both-screen-and-file-inside-a-shell-script
Descubrí que en zsh, la solución here-doc se puede modificar utilizando el constructo "multios" para copiar la salida a stdout / stderr y al archivo de registro:
#!/bin/zsh
LOG=$0.log
# 8 is an arbitrary number;
# multiple redirects for the same file descriptor
# triggers "multios"
. 8<</EOF /dev/fd/8 2>&2 >&1 2>>$LOG >>$LOG
# some commands
date >&2
set -x
echo hi
echo bye
EOF
echo not logged
No es tan legible como la solución exec
, pero tiene la ventaja de permitirle registrar solo una parte del script. Por supuesto, si omite el EOF, todo el script se ejecuta con el registro. No estoy seguro de cómo zsh
implementa multios, pero puede tener menos gastos generales que tee
. Desafortunadamente parece que uno no puede usar multios con exec
.
He encontrado una forma de obtener el resultado deseado. Aunque puede ser de alguna manera poco ortodoxa. De todos modos aquí va. En el archivo redir.env tengo el siguiente código:
#####redir.env#####
export LOG_FILE=log.txt
exec 2>>${LOG_FILE}
function log {
echo "$1">>${LOG_FILE}
}
function message {
echo "$1"
echo "$1">>${LOG_FILE}
}
Luego, en el guión real, tengo los siguientes códigos:
#!/bin/sh
. redir.env
echo "Echoed to console only"
log "Written to log file only"
message "To console and log"
echo "This is stderr. Written to log file only" 1>&2
Aquí, echo sale solo a la consola, registra las salidas para solo registrar el archivo y las salidas de mensajes tanto para el archivo de registro como para la consola.
Después de ejecutar el archivo de script anterior, tengo los siguientes resultados:
En la consola
En la consola
Echoed to console only
Para consolar y registrar
Para el archivo de registro
En archivo de registro escrito solo para el archivo de registro
Esto es stderr Escrito solo para el archivo de registro
Para consolar y registrar
Espero que esto ayude.
Intenté la respuesta de Joonty, pero también obtuve
ejecutivo: 1: no encontrado
error. Esto es lo que funciona mejor para mí (se confirmed que también funciona en zsh):
#!/bin/bash
LOG_FILE=/tmp/both.log
exec > >(tee -a ${LOG_FILE} )
exec 2> >(tee -a ${LOG_FILE} >&2)
echo "this is stdout"
chmmm 77 /makeError
El archivo /tmp/both.log contiene luego
this is stdout
chmmm command not found
El /tmp/both.log se agrega a menos que elimine el -a del tee.
Prueba esto, hará el trabajo:
log_file=$curr_dir/log_file.txt
exec > >(tee -a ${log_file} )
exec 2> >(tee -a ${log_file} >&2)
Quería mostrar los registros en stdout y el archivo de registro junto con la marca de tiempo. Ninguna de las respuestas anteriores funcionó para mí. Hice uso de la sustitución de procesos y el comando exec y se me ocurrió el siguiente código. Registros de muestra:
2017-06-21 11:16:41+05:30 Fetching information about files in the directory...
Agregue las siguientes líneas en la parte superior de su secuencia de comandos:
LOG_FILE=script.log
exec > >(while read -r line; do printf ''%s %s/n'' "$(date --rfc-3339=seconds)" "$line" | tee -a $LOG_FILE; done)
exec 2> >(while read -r line; do printf ''%s %s/n'' "$(date --rfc-3339=seconds)" "$line" | tee -a $LOG_FILE; done >&2)
Espero que esto ayude a alguien!
Sí, quieres usar tee
:
tee - leer desde entrada estándar y escribir en salida estándar y archivos
Simplemente canalice su comando a la T y pase el archivo como un argumento, de esta manera:
exec 1 | tee ${LOG_FILE}
exec 2 | tee ${LOG_FILE}
Esto imprime la salida a STDOUT y escribe la misma salida en un archivo de registro. Ver man tee
para más información.
Tenga en cuenta que esto no escribirá stderr en el archivo de registro, por lo que si desea combinar las dos secuencias, utilice:
exec 1 2>&1 | tee ${LOG_FILE}
para el archivo de registro puede fechar para ingresar datos de texto. El siguiente código puede ayudar
# declaring variables
Logfile="logfile.txt"
MAIL_LOG="Message to print in log file"
Location="were is u want to store log file"
cd $Location
if [ -f $Logfile ]
then
echo "$MAIL_LOG " >> $Logfile
else
touch $Logfile
echo "$MAIL_LOG" >> $Logfile
fi
salida: 2. El archivo de registro se creará en la primera ejecución y continuará actualizando desde las siguientes ejecuciones. En caso de que falte el archivo de registro en una ejecución futura, el script creará un nuevo archivo de registro.
#
#------------------------------------------------------------------------------
# echo pass params and print them to a log file and terminal
# with timestamp and $host_name and $0 PID
# usage:
# doLog "INFO some info message"
# doLog "DEBUG some debug message"
# doLog "WARN some warning message"
# doLog "ERROR some really ERROR message"
# doLog "FATAL some really fatal message"
#------------------------------------------------------------------------------
doLog(){
type_of_msg=$(echo $*|cut -d" " -f1)
msg=$(echo "$*"|cut -d" " -f2-)
[[ $type_of_msg == DEBUG ]] && [[ $do_print_debug_msgs -ne 1 ]] && return
[[ $type_of_msg == INFO ]] && type_of_msg="INFO " # one space for aligning
[[ $type_of_msg == WARN ]] && type_of_msg="WARN " # as well
# print to the terminal if we have one
test -t 1 && echo " [$type_of_msg] `date "+%Y.%m.%d-%H:%M:%S %Z"` [$run_unit][@$host_name] [$$] ""$msg"
# define default log file none specified in cnf file
test -z $log_file && /
mkdir -p $product_instance_dir/dat/log/bash && /
log_file="$product_instance_dir/dat/log/bash/$run_unit.`date "+%Y%m"`.log"
echo " [$type_of_msg] `date "+%Y.%m.%d-%H:%M:%S %Z"` [$run_unit][@$host_name] [$$] ""$msg" >> $log_file
}
#eof func doLog
exec 3>&1 1>>${LOG_FILE} 2>&1
enviaría salida stdout y stderr al archivo de registro, pero también te dejaría con fd 3 conectado a la consola, por lo que puedes hacer
echo "Some console message" 1>&3
escribir un mensaje solo a la consola, o
echo "Some console and log file message" | tee /dev/fd/3
para escribir un mensaje tanto en la consola como en el archivo de registro: tee
envía su salida a su propio fd 1 (que aquí es el LOG_FILE
) y al archivo que le indicó que escribiera (que aquí es fd 3, es decir, la consola) .
Ejemplo:
exec 3>&1 1>>${LOG_FILE} 2>&1
echo "This is stdout"
echo "This is stderr" 1>&2
echo "This is the console (fd 3)" 1>&3
echo "This is both the log and the console" | tee /dev/fd/3
imprimiría
This is the console (fd 3)
This is both the log and the console
en la consola y poner
This is stdout
This is stderr
This is both the log and the console
en el archivo de registro.