it-swarm.com.ru

Запись результатов в файл журнала и консоль

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

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

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

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

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

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

70
abinash shrestha
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), так и в файл, в который вы сказали записать (который здесь это фд 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

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

79
Ian Roberts

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

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

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

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

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

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

exec 1 2>&1 | tee ${LOG_FILE}
33
Jon Cairns

Я попробовал ответ Джоунти, но я также получил 

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, как если бы это был файл.

27
alfonx

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

# 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. Файл журнала будет создан при первом запуске и продолжит обновление после следующих запусков. В случае отсутствия файла журнала при последующем запуске, скрипт создаст новый файл журнала.

3
user2197712

Я хотел показать журналы на стандартный вывод и файл журнала вместе с отметкой времени. Ни один из приведенных выше ответов не помог мне. Я использовал команду процесс подстановки и 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)

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

3
Jyoti Dhiman

Я нашел способ получить желаемый результат. Хотя это может быть несколько неортодоксальным способом. В любом случае здесь это идет. В файле 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}
    }

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

#!/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 выводит только на консоль, log выводит только на файл журнала и message выводит как на файл журнала, так и на консоль.

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

В консоли

В консоли
Только для консоли
Чтобы утешить и войти

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

В файле журнала Записано только в лог файл
Это Стдерр. Записано только в лог файл
Чтобы утешить и войти

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

1
abinash shrestha
    #
    #------------------------------------------------------------------------------
    # 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
1
Yordan Georgiev

Я считаю очень полезным добавлять как stdout, так и stderr в файл журнала. Я был рад видеть решение alfonx с exec > >(tee -a), потому что мне было интересно, как это сделать с помощью exec. Я столкнулся с креативным решением с использованием синтаксиса here-doc и .: https://unix.stackexchange.com/questions/80707/how-to-output-text-to-both-screen-and-file-inside- a-Shell-скрипт

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

0
Metamorphic

Попробуйте это, это сделает работу:

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