Linux bash脚本如何为exec &>>输出添加日期时间日志前缀
问题解决方法
核心需要解决两个问题:
- 你当前定义的
LOG/ERROR_LOG变量是脚本启动时就固定了时间戳,所有日志都会用同一个时间,不符合实际输出时间的需求 - 第三方命令(s3cmd)的输出没有经过你的前缀处理,直接写入日志导致格式断裂
1. 替换固定日志前缀为动态生成的日志函数
封装通用日志函数,每次调用时动态生成时间戳,同时支持直接传参输出、接收管道输入给每一行加前缀两种场景:
LOG_FILE=$(basename "$0" | cut -f 1 -d '.') # 定义INFO级别日志函数 log_info() { local prefix="[$(date '+%Y-%m-%d %H:%M:%S,%3N')] INFO {$LOG_FILE} - " if [ $# -gt 0 ]; then echo "${prefix}$*" else while IFS= read -r line; do echo "${prefix}${line}" done fi } # 定义ERROR级别日志函数 log_error() { local prefix="[$(date '+%Y-%m-%d %H:%M:%S,%3N')] ERROR {$LOG_FILE} - " if [ $# -gt 0 ]; then echo "${prefix}$*" else while IFS= read -r line; do echo "${prefix}${line}" done fi }
2. 修改s3cmd调用逻辑
- 给s3cmd加
--no-progress参数,关闭动态刷新的进度条输出,避免生成无意义的控制字符和碎行 - 把s3cmd的所有输出(标准输出+错误输出)通过管道传给
log_info函数,每一行自动加上统一前缀
# 原s3cmd调用替换为如下写法 s3cmd put --no-progress -c /home/config/.s3cfg "$file" "$S3_PUSH"/ 2>&1 | log_info
3. 其他必要优化(建议保留)
- 不要用
ls遍历文件,直接用glob匹配避免文件名带空格/特殊字符时报错 - 已经用
exec &>> $LOG_PATH做了全局输出重定向,不需要再给每个echo重复指定>> $LOG_PATH - 提前创建日志目录避免路径不存在时报错
修改后完整脚本
#!/bin/bash CURR_DIR=$(dirname "$0") SCRIPT_NAME="$(basename "$0")" LOG_FILE=$(echo "$SCRIPT_NAME" | cut -f 1 -d '.') TODAY=$(date '+%Y-%m-%d') LOG_PATH="$CURR_DIR"/logs/"$LOG_FILE"-"$TODAY".log # 提前创建日志目录 mkdir -p "$(dirname "$LOG_PATH")" # 定义INFO级别日志函数,支持直接传参和管道输入 log_info() { local prefix="[$(date '+%Y-%m-%d %H:%M:%S,%3N')] INFO {$LOG_FILE} - " if [ $# -gt 0 ]; then echo "${prefix}$*" else while IFS= read -r line; do echo "${prefix}${line}" done fi } # 定义ERROR级别日志函数 log_error() { local prefix="[$(date '+%Y-%m-%d %H:%M:%S,%3N')] ERROR {$LOG_FILE} - " if [ $# -gt 0 ]; then echo "${prefix}$*" else while IFS= read -r line; do echo "${prefix}${line}" done fi } BUCKET="s3.bucket.example" OUT_FOLDER="path/to/folderA" S3_PUSH="s3://$BUCKET/$OUT_FOLDER" # 全局输出重定向到日志文件 exec &>> "$LOG_PATH" log_info "Copying files to local out folder..." cp /path/to/folderA/*.* /path/to/folderB log_info "Command returned code: $?" # 用glob判断文件是否存在,避免ls的兼容性问题 shopt -s nullglob files=(/path/to/folderA/*) if [ ${#files[@]} -gt 0 ]; then for file in "${files[@]}" ; do # 跳过目录只处理文件 [ -f "$file" ] || continue log_info "File $file found for sync" log_info "Pushing $file to S3 /Folder..." # s3cmd所有输出自动加前缀 s3cmd put --no-progress -c /home/config/.s3cfg "$file" "$S3_PUSH"/ 2>&1 | log_info s3_rc=$? log_info "s3cmd command returned code: $s3_rc" log_info "Copying $file to local backup..." mv "$file" /path/to/folderA/backup/ mv_rc=$? log_info "mv command returned code: $mv_rc" if [ $mv_rc -ne 0 ]; then log_error "Failed to move $file to backup folder, return code: $mv_rc" fi done else log_info "No files found for sync." fi
修改后所有s3cmd的输出行都会带上统一的时间、脚本名前缀,完全符合你的grok解析规则,不会再出现无前缀的异常行。
内容的提问来源于stack exchange,提问作者Jefledge
相关产品推荐
相关产品推荐

