Запись выходов в файл журнала и консоль
В оболочке Unix у меня есть файл env (файл env определяет параметры, необходимые для запуска пользователя script, как имя файла журнала и путь, перенаправление выходов и ошибок в файл журнала, сведения о подключении к базе данных и т.д.), который перенаправляет все выходы (эхо-сообщения) и ошибки в файл журнала из выполненного script, используя следующий код:
exec 1>>${LOG_FILE}
exec 2>>${LOG_FILE}
Файл env выполняется в начале каждого script. Из-за вышеприведенного кода в файле env все выходы консоли, которые могут быть выведены пользователем или ошибки, непосредственно выводятся в файл журнала, который мне действительно нужен.
Но есть некоторые выборочные пользовательские выходы, которые я хочу отображать как в консоли, так и в файле журнала. Но из-за вышеприведенного кода я не могу этого сделать.
Я знаю, что если я удалю вышеуказанный код, я могу получить желаемый результат для этого случая, но мне придется вручную записывать все остальные выходы в файл журнала, что непростая задача.
Есть ли способ получить вывод как в консоли, так и в файле журнала без удаления вышеуказанных кодов?
Ответы
Ответ 1
exec 3>&1 1>>${LOG_FILE} 2>&1
отправит вывод stdout и stderr в файл журнала, но также оставит вас с fd 3, подключенным к консоли, чтобы вы могли сделать
echo "Some console message" 1>&3
чтобы написать сообщение только на консоли, или
echo "Some console and log file message" | tee /dev/fd/3
чтобы написать сообщение как на консоль, так и на файл журнала - tee
отправляет свой вывод как своему собственному fd 1 (который находится здесь LOG_FILE
), так и файл, который вы ему написали (который здесь fd 3, т.е. консоль).
Пример:
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
будет печатать
This is the console (fd 3)
This is both the log and the console
на консоли и поместите
This is stdout
This is stderr
This is both the log and the console
в файл журнала.
Ответ 2
Да, вы хотите использовать tee
:
tee - чтение со стандартного ввода и запись на стандартный вывод и файлы
Просто передайте свою команду в tee и передайте файл в качестве аргумента, например:
exec 1 | tee ${LOG_FILE}
exec 2 | tee ${LOG_FILE}
Это и выводит вывод на STDOUT, и записывает один и тот же результат в файл журнала. Подробнее см. man tee
.
Обратите внимание, что это не будет записывать stderr в файл журнала, поэтому, если вы хотите объединить два потока, используйте:
exec 1 2>&1 | tee ${LOG_FILE}
Ответ 3
Я попробовал joonty ответить, но я также получил
exec: 1: не найдено
ошибка. Это то, что лучше всего работает для меня (также подтверждено работать в 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
Файл /tmp/both.log впоследствии содержит
this is stdout
chmmm command not found
/Tmp/both.log добавляется, если вы не удалите -a из тройника.
Подсказка: >(...)
это подстановка процесса. Это позволяет exec
команде tee
как если бы это был файл.
Ответ 4
для файла журнала, который вы можете ввести для ввода текстовых данных. следующий код может помочь
# 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
ouput: 2. Файл журнала будет создан в первом запуске и продолжит обновление после следующих запусков. Если файл журнала отсутствует в будущем, script создаст новый файл журнала.
Ответ 5
Я хотел отображать журналы в файле stdout и log вместе с меткой времени. Ни один из вышеперечисленных ответов не работал у меня.
Я использовал команду подстановки процесса и exec и придумал следующий код.
Журналы выборок:
2017-06-21 11:16:41+05:30 Fetching information about files in the directory...
Добавьте следующие строки вверху вашего script:
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)
Надеюсь, это поможет кому-то!
Ответ 6
Я нашел способ получить желаемый результат. Хотя это может быть несколько неортодоксальным способом. В любом случае, здесь. В файле redir.env у меня есть следующий код:
#####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}
}
Тогда в фактическом script у меня есть следующие коды:
#!/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
Здесь echo выводит только на консоль, журнал выходы только для файлов журнала и сообщений, как для файла журнала, так и для консоли.
После выполнения вышеуказанного файла script у меня есть следующие выходы:
В консоли
В консоли
Отправлено только на консоль
Чтобы консоль и журнал
Для файла журнала
В файле журналаНаписано только для файла журнала Это stderr. Написано только для файла журнала Чтобы консоль и журнал
Надеюсь на эту помощь.
Ответ 7
#
#------------------------------------------------------------------------------
# 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
Ответ 8
Мне очень полезно добавить как stdout, так и stderr в файл журнала. Я был рад увидеть решение alfonx с exec > >(tee -a)
, потому что мне было интересно, как это сделать, используя exec
. Я наткнулся на креативное решение, используя синтаксис здесь-doc и .
: https://unix.stackexchange.com/questions/80707/how-to-output-text-to-both-screen-and-file-inside-a-shell-script
Я обнаружил, что в zsh решение здесь-doc может быть изменено с использованием конструкции "multios" для копирования вывода на stdout/stderr и файл журнала:
#!/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
Он не так читается, как решение exec
, но имеет то преимущество, что позволяет вам регистрировать только часть script. Конечно, если вы опускаете EOF, тогда весь script выполняется с протоколированием. Я не уверен, как zsh
реализует multios, но может иметь меньше накладных расходов, чем tee
. К сожалению, кажется, что нельзя использовать multios с exec
.
Ответ 9
Попробуйте это, он выполнит работу:
log_file=$curr_dir/log_file.txt
exec > >(tee -a ${log_file} )
exec 2> >(tee -a ${log_file} >&2)