BASH 脚本中用于日志记录的 SDERR 和 STDOUT 文件描述符

BASH 脚本中用于日志记录的 SDERR 和 STDOUT 文件描述符

我正在尝试将基本日志记录添加到将由 cron 作业每天运行的脚本中。基本上是这样的:

LOGFILE=mylog.txt
exec 3<>$LOGFILE
2>&1
commands
...
exec 3>&-

基本上我需要知道的就是如何正确地编写第三行,以便 STDERR 和 STDOUT 都写入 FD 3,即日志文件。我一直在摸索,遗憾的是 TLDP 的解释不是最好的 - 而且大多数关于重定向和文件描述符的其他教程都没有深入到这种程度。任何帮助都将不胜感激。

答案1

exec >&3 2>&3

SF 要求我输入更多字符,但仅此而已。

答案2

我使用它进行简单的日志记录:

exec > >(tee -a $LOGFILE)
exec 2> >(tee -a >(sed 's/^/STDERR: /' >>$LOGFILE) 1>&2)

对于复杂的东西,我在 log-function.sh 中有一个函数:

log() { #{{{
    local DAYS_TO_KEEP_THE_LOG=30
    local LOG_DATE_FORMAT="+%Y-%m-%d %H:%M:%S"
    local FILESUFIX_DATE_FORMAT="+%Y-%m-%d_%H%M%S"
    case $1 in
        --disable-output-redirection)
            OUTPUT_NOT_LOGGED=1
            log Output redirection is disabled. Only explicit \"log\" calls will be logged.
            return
            ;;
        --enable-timestamps)
            if [[ $OUTPUT_NOT_LOGGED == 1 ]];then
                log The option --enable-timestamps is ignored if --disable-output-redirection is used.
            fi
            TIMESTAMP_ON_OUTPUT=1
            log Time stamps enabled for output.
            return
            ;;
        --enable-syslog)
            ENABLE_SYSLOG=1
            return
            ;;
        --log-file)
            if [ $# -eq 2 ];then
                local MY_LOG_FILE_TEMP=$2
                local MY_LOG_DIR_TEMP=$(dirname $MY_LOG_FILE_TEMP)
                if [ ! -d $MY_LOG_DIR_TEMP ];then
                    log Folder $MY_LOG_DIR_TEMP does not exist. It will be created.
                    log "$(mkdir -p $MY_LOG_DIR_TEMP)"
                fi
                log Current log file is: $MY_LOG_FILE_TEMP
                log Rotating the logs
                # We make sure that the current log file is not deleted. We change the mtime to be current time.
                log "$(touch $MY_LOG_FILE_TEMP)"
                # Find all log files that have a date appended, older than 14 days and remove them.
                #log "$(find $(dirname $MY_LOG_FILE_TEMP) -name $(basename $MY_LOG_FILE_TEMP)-\* -mtime +$DAYS_TO_KEEP_THE_LOG -print0|xargs -0r rm -v)"
                log "$(find $(dirname $MY_LOG_FILE_TEMP) -name $(basename $MY_LOG_FILE_TEMP)-\* -mtime +$DAYS_TO_KEEP_THE_LOG|xargs rm 2>/dev/null)"
                # rename the log file and append the current date and time to the filename.
                #log "$(mv -v  $MY_LOG_FILE_TEMP $MY_LOG_FILE_TEMP-$(date "$FILESUFIX_DATE_FORMAT"))"
                log "$(echo $MY_LOG_FILE_TEMP '->' $MY_LOG_FILE_TEMP-$(date "$FILESUFIX_DATE_FORMAT");mv $MY_LOG_FILE_TEMP $MY_LOG_FILE_TEMP-$(date "$FILESUFIX_DATE_FORMAT"))"

                # Dump the log memory buffer into the log file.
                if [ "x$MY_LOG" != "x" ];then
                    echo -e "$MY_LOG" >>$MY_LOG_FILE_TEMP
                    unset MY_LOG
                fi
                if [[ $MY_LOG_FILE_TEMP =~ '^[^/]' ]]; then
                    log Full path of the log is $PWD/$MY_LOG_FILE_TEMP
                fi
                MY_LOG_FILE=$MY_LOG_FILE_TEMP
                if [[ $OUTPUT_NOT_LOGGED != 1 ]];then
                    if [[ $TIMESTAMP_ON_OUTPUT == 1 ]];then
                        exec > >(while read LINE; do echo $(date "$LOG_DATE_FORMAT") ">" $LINE; done|tee -a $MY_LOG_FILE) 2>&1
                    else
                        exec > >(tee -a $MY_LOG_FILE)
                        exec 2> >(tee -a >(sed 's/^/ERR: /' >>$MY_LOG_FILE) 1>&2)
                    fi
                fi
                return
            else
                log "Invalid number of paramaters for the log function"
            fi
            ;;
        --help|--*)
            echo 'This function allows to log inside a script. It can be used to log the entire output to a log file.'
            echo 'Examples:'
            echo '       log "Message to log"'
            echo '       log --log-file FILENAME.LOG'
            echo '       log --enable-timestamps;log --log-file FILENAME.LOG'
            echo '       log --disable-output-redirection;log --log-file FILENAME.LOG'
            echo '       log --enable-syslog'
            return
            ;;
        "")     # If the message is empty, then do not log anything.
            return
            ;;
    esac

    # We log to the console to STDERR then to syslog.
    if [[ $ENABLE_SYSLOG == 1 ]];then
        logger -p local1.notice -t $(basename $0) -i -- "$@"
    fi

    if [ "x$MY_LOG_FILE" = "x" ]; then
        echo $(date "$LOG_DATE_FORMAT") "$@" >&2
        # If we do not have a log file configured, we will buffer the log in memory.
        if [ "x$MY_LOG" = "x" ];then
            MY_LOG="$(date "$LOG_DATE_FORMAT") . $@"
        else
            MY_LOG="$MY_LOG\n$(date "$LOG_DATE_FORMAT") . $@"
        fi
    else
        if [[ $OUTPUT_NOT_LOGGED != 1 ]];then
            if [[ $TIMESTAMP_ON_OUTPUT == 1 ]];then
                echo "$@" >&2
            else
                echo $(date "$LOG_DATE_FORMAT") "$@" >&2
            fi
        else
            echo $(date "$LOG_DATE_FORMAT") "$@" >&2
            echo $(date "$LOG_DATE_FORMAT") "$@" >> $MY_LOG_FILE
        fi
    fi
} #}}}
#vim:ts=4:sw=4:et:fdm=marker:

以下是它的用法:

SCRIPT_HOME=$(cd $(dirname $0);pwd -P)
. $SCRIPT_HOME/log-function.sh
log --enable-syslog
log --log-file $SCRIPT_HOME/logs/$(basename $0).log
log Starting $0 script with params=$@ on $(hostname) host as $USER user.

相关内容