使用awk统计nginx access log中最近1消失访问数最多的10个ip

  1. 先筛选出最近 1 小时的日志行
  2. 再用 awk 提取 IP 并统计

由于 Nginx 默认日志时间格式为:
[14/Jan/2026:21:34:12 +0800](注意:当前系统时间是 2026-01-14 21:34


推荐方案:使用 awk + 时间比较(精确、高效)

# 获取当前时间(用于计算1小时前)
now=$(date '+%s')
one_hour_ago=$((now - 3600))

awk -v cutoff="$one_hour_ago" '
{
    # 提取时间字段:第4列,格式如 [14/Jan/2026:21:34:12
    time_str = $4
    gsub(/\[/, "", time_str)        # 去掉 [
    
    # 转换为时间戳(GNU awk 支持 mktime)
    split(time_str, parts, /[:/\]/)
    day = parts[1]
    month = parts[2]
    year = parts[3]
    hour = parts[4]
    minute = parts[5]
    second = parts[6]

    # 月份转数字
    months["Jan"] = "01"; months["Feb"] = "02"; months["Mar"] = "03"
    months["Apr"] = "04"; months["May"] = "05"; months["Jun"] = "06"
    months["Jul"] = "07"; months["Aug"] = "08"; months["Sep"] = "09"
    months["Oct"] = "10"; months["Nov"] = "11"; months["Dec"] = "12"

    mon_num = months[month]
    if (mon_num == "") next

    # 构造 ISO 时间字符串并转时间戳
    cmd = "date -d \"" year "-" mon_num "-" day " " hour ":" minute ":" second "\" +%s 2>/dev/null"
    cmd | getline log_time
    close(cmd)

    if (log_time >= cutoff) {
        print $1
    }
}
' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -10

⚠️ 缺点:每行都调用 date 命令,大日志文件会很慢


更高效方案:用 date 生成时间范围 + grep 初筛(推荐)

步骤:

  1. 生成 1 小时前的时间字符串(如 [14/Jan/2026:20:
  2. awksed 提取从该时间开始的所有日志
  3. 再统计 IP
# 1. 获取1小时前的“日/月/年:小时”格式(用于匹配日志)
start_time=$(date -d '1 hour ago' '+%d/%b/%Y:%H')

# 2. 提取从 start_time 开始的所有日志行(包含之后所有分钟)
awk -v start="$start_time" '
$0 ~ "\\[" start {
    in_range = 1
}
in_range {
    print $1
}
' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -10

原理:

  • Nginx 日志按时间顺序写入(假设未 rotate)
  • 一旦匹配到 [14/Jan/2026:20,后面所有行都是 ≥ 20:00 的
  • 所以从第一个匹配行开始,后续全部属于最近1小时

✅ 优点:不解析每行时间,速度极快,适合大日志
❌ 缺点:如果日志不是严格按时间排序(如多 worker 写入乱序),可能不准(但 Nginx 默认是顺序的)


最佳实践(兼顾准确与性能)

如果你的日志是标准格式且按时间排序(绝大多数情况),用下面这个 简洁高效版

# 获取1小时前的时间前缀,例如 "14/Jan/2026:20"
prefix=$(date -d '1 hour ago' '+%d/%b/%Y:%H')

# 从匹配该前缀的第一行开始,提取所有IP并统计
awk -v p="$prefix" '
match($0, /\[([^\]]+)/, m) {
    if (m[1] >= p ":00") {
        print $1
    }
}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -10

💡 m[1] >= p ":00" 确保时间字符串比较正确(如 14/Jan/2026:20:30 > 14/Jan/2026:20:00


补充:处理日志轮转(access.log.1, .gz 等)

如果需要包含压缩日志(如 logrotate 后的):

# 合并当前 + 上一个日志
zcat -f /var/log/nginx/access.log* | awk -v p="$prefix" '
match($0, /\[([^\]]+)/, m) {
    if (m[1] >= p ":00") {
        print $1
    }
}' | sort | uniq -c | sort -nr | head -10

zcat -f 可同时处理 .gz 和未压缩文件


总结:推荐命令(直接复制使用)

prefix=$(date -d '1 hour ago' '+%d/%b/%Y:%H')
awk -v p="$prefix" '
match($0, /\[([^\]]+)/, m) {
    if (m[1] >= p ":00") {
        print $1
    }
}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -10

Comments

No comments yet. Why don’t you start the discussion?

发表回复