![BASH 脚本中用于日志记录的 SDERR 和 STDOUT 文件描述符](https://linux22.com/image/568963/BASH%20%E8%84%9A%E6%9C%AC%E4%B8%AD%E7%94%A8%E4%BA%8E%E6%97%A5%E5%BF%97%E8%AE%B0%E5%BD%95%E7%9A%84%20SDERR%20%E5%92%8C%20STDOUT%20%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.png)
我正在尝试将基本日志记录添加到将由 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.