Подтвердить что ты не робот

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

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

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

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

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

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

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

4b9b3361

Ответ 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)