Запись выходных данных в файл журнала и консоль


в оболочке Unix у меня есть env-файл (env file определяет параметры, необходимые для запуска пользовательского скрипта, такие как имя и путь файла журнала, перенаправление выходов и ошибок в файл журнала, сведения о подключении к базе данных и т. д.), который перенаправляет все выходы (сообщения Эхо) и ошибки в файл журнала из выполненного скрипта с использованием следующего кода:

exec 1>>${LOG_FILE}
exec 2>>${LOG_FILE}

env-файл выполняется в начале каждого скрипта. Из-за вышеуказанного кода в файле env все консольные выходы, которые могут быть пользовательскими выходами или ошибками, непосредственно выводятся в файл журнала, который мне действительно нужен.

но есть некоторые выборочные пользовательские выходы, которые я хочу отображать как в консоли, так и в файле журнала. Но из-за вышеприведенного кода я не могу этого сделать.

Я знаю, что если я удалю приведенный выше код, я могу получить желаемый результат для этого случая, но мне придется вручную записать все остальные выходные данные в файл журнала, который не является простым задача.

есть ли способ получить вывод как в консоли, так и в файле журнала без удаления вышеуказанных кодов?

9 62

9 ответов:

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

в файл журнала.

Да, вы хотите использовать tee:

тройник-чтение из стандартного ввода и запись в стандартный вывод и файлы

просто передайте свою команду в tee и передайте файл в качестве аргумента, например:

exec 1 | tee ${LOG_FILE}
exec 2 | tee ${LOG_FILE}

Это оба выводит вывод на STDOUT и записывает тот же вывод в файл журнала. Смотрите man tee для получения дополнительной информации.

обратите внимание, что это не будет записывать stderr в файл журнала, так что если вы хотите объединить два потока, то использование:

exec 1 2>&1 | tee ${LOG_FILE}

Я попытался ответить Джунти, но я также получил

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 / оба.журнал после этого содержит

this is stdout
chmmm command not found 

/tmp / оба.журнал добавляется, если вы не удалите из тройника.

для файла журнала вы можете ввести дату в текстовые данные. следующий код может помочь

# 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  

выход: 2. Файл журнала будет создан в первом запуске и продолжать обновляться со следующих запусков. Если файл журнала отсутствует в будущем запуске , скрипт создаст новый файл журнала.

Я хотел отобразить журналы на stdout и файл журнала вместе с меткой времени. Ни один из ответов не работал для меня. Я использовал подмена процесса и exec команда и придумал следующий код. Примеры журналов:

2017-06-21 11:16:41+05:30 Fetching information about files in the directory...

добавить следующие строки в верхней части вашего скрипта:

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)

надеюсь, что это поможет кому-то!

Я нашел способ получить желаемый результат. Хотя это может быть несколько необычным способом. В любом случае здесь он идет. В перенаправителя.env файл у меня есть следующий код:

#####redir.env#####    
export LOG_FILE=log.txt

      exec 2>>${LOG_FILE}

    function log {
     echo "">>${LOG_FILE}
    }

    function message {
     echo ""
     echo "">>${LOG_FILE}
    }

тогда в самом скрипте у меня есть следующие коды:

#!/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

здесь Эхо выходы только на консоль,log выводит только файл журнала и выводит данные как в файл журнала, так и в консоль.

после выполнения указанного выше файла скрипта I есть следующие выходы:

в консоли

в консоли
Эхом откликнулся на утешение только
Чтобы утешить и войти

для файла журнала

В Файле Журнала Записывается только в файл журнала
Это поток stderr. Записывается только в файл журнала
Чтобы утешить и войти

надеюсь, что это поможет.

    #
    #------------------------------------------------------------------------------
    # echo pass params and print them to a log file and terminal
    # with timestamp and $host_name and  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

Я считаю очень полезным добавить как 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 решение here-doc можно изменить с помощью " multios" построить для копирования вывода в stdout/stderr и файл журнала:

#!/bin/zsh
LOG=.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 решение, но оно имеет то преимущество, что позволяет войти только часть сценария. Конечно, если вы опустите EOF, то весь скрипт выполняется с журналированием. Я не уверен, как zsh реализует multios, но он может иметь меньше накладных расходов, чем tee. К сожалению, кажется, что нельзя использовать multios с exec.

попробуйте это, он будет делать работу:

log_file=$curr_dir/log_file.txt
exec > >(tee -a ${log_file} )
exec 2> >(tee -a ${log_file} >&2)