#!/bin/bash if [ $# -ne 1 ]; then echo "Usage...
Erstellt am: 10. Dezember 2025
Erstellt am: 10. Dezember 2025
#!/bin/bash
if [ # -ne 1 ]; then
echo "Usage: 0 <HADOOP_HOME>"
echo "Example: $0 /export/jcloud-hadoop/hadoop-2.7.3-server"
exit 1
fi
HADOOP_HOME={HADOOP_HOME}/ranger_server_test.out
MAX_MEM_THRESHOLD=5 # 内存阈值,单位GB,可修改
PROCESS_STATE="DOWN"
if pgrep -f "loop_ranger_server_test.sh" > /dev/null; then
PROCESS_STATE="UP"
fi
YESTERDAY_START=$(date -d "yesterday 00:00:00" '+%Y-%m-%d %H:%M:%S')
LATEST_SUCCESS_LOOP=0
if [ -f "{RECORD_FILE}" ]; then
# 使用awk来处理时间范围内的PASS记录
LATEST_SUCCESS_LOOP=(awk -v start_time="YESTERDAY_START" '
/PASS/ {
# 提取时间戳 (格式: 2024-01-01 12:30:45)
match(0, /[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/)
if (RSTART > 0) {
log_time = substr(0, RSTART, RLENGTH)
if (log_time >= start_time) {
count++
}
}
}
END { print count+0 }
' {RECORD_FILE})
fi
CURRENT_LOOP={RECORD_FILE} 2>/dev/null | tail -1 | grep -o "loop: [0-9]*" | cut -d' ' -f2)
if [ -z "$CURRENT_LOOP" ]; then
CURRENT_LOOP=0
fi
YHDFS_MEM=(ssh 11.241.202.184 "ps aux | grep -v grep | grep 'jd.jdufs.server.JdufsServer' | awk '{print \6}' | head -1")
if [ ! -z "(echo "scale=1; {YHDFS_MEM_GB}g"
# 判断内存是否超过阈值
MEM_OK=YHDFS_MEM_GB < $MAX_MEM_THRESHOLD" | bc)
else
YHDFS_MEM_INFO="N/A"
MEM_OK=0
fi
echo "loop ranger server test script process state: {LATEST_SUCCESS_LOOP}, current loop: {YHDFS_MEM_INFO}"
分析一下这个代码 特别是时间的那一段代码 为什么要这么设计,你能举个案例出来么?
下面我会逐段解释脚本逻辑,尤其是你重点关注的处理昨天 0 点之后 PASS 次数的时间过滤那段 awk 代码,并给你一个**完整示例(包含日志内容与计算过程)**帮助理解为何这样设计。
这个脚本用来监控 ranger server 的循环测试情况,包括:
你关心的部分如下:
bash# 获取昨天0点的时间戳 YESTERDAY_START=$(date -d "yesterday 00:00:00" '+%Y-%m-%d %H:%M:%S') # 获取从昨天0点开始到现在的成功循环次数 LATEST_SUCCESS_LOOP=$(awk -v start_time="$YESTERDAY_START" ' /PASS/ { match($0, /[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/) if (RSTART > 0) { log_time = substr($0, RSTART, RLENGTH) if (log_time >= start_time) { count++ } } } END { print count+0 } ' ${RECORD_FILE})
也就是说:
不能统计更早的 PASS
也不能统计未来的 PASS
因此要做两个关键动作:
bashYESTERDAY_START="2024-02-10 00:00:00"
因为日志格式类似:
text2024-02-10 01:23:45 PASS loop: 123 2024-02-09 22:00:12 PASS loop: 100
所以必须通过正则提取时间:
awkmatch($0, /YYYY-MM-DD HH:MM:SS/)
关键点:
YYYY-MM-DD HH:MM:SS 这种格式可以直接字符串比较大小!
例如:
text"2024-02-10 01:00:00" > "2024-02-10 00:00:00" → true "2024-02-09 23:59:59" < "2024-02-10 00:00:00" → true
因此这样设计是为了避免复杂的时间戳转换。
假设今天是 2024-02-11
📌 脚本算出:
YESTERDAY_START="2024-02-10 00:00:00"
你的 ranger_server_test.out 内容如下:
text2024-02-09 21:00:01 PASS loop: 50 2024-02-10 01:20:10 PASS loop: 60 2024-02-10 10:15:33 PASS loop: 61 2024-02-10 23:59:59 PASS loop: 62 2024-02-11 01:00:00 PASS loop: 70
2024-02-09 21:00:01 PASS loop: 50
提取时间:2024-02-09 21:00:01
比较:
2024-02-09 21:00:01 >= 2024-02-10 00:00:00 ? false
→ 不计数
2024-02-10 01:20:10 PASS loop: 60
2024-02-10 01:20:10 >= 2024-02-10 00:00:00 ? true
→ count = 1
2024-02-10 10:15:33 PASS loop: 61
>= 2024-02-10 00:00:00 → true
→ count = 2
2024-02-10 23:59:59 PASS loop: 62
符合
→ count = 3
2024-02-11 01:00:00 PASS loop: 70
虽然在今天,仍然 >= 昨天 0 点
→ 符合需求(昨天 0 点到现在)
→ count = 4
LATEST_SUCCESS_LOOP = 4
原因如下:
必须用正则匹配时间戳。
字符串比较即可判断时间顺序。
天然可排序,因此无需复杂操作。
| 方法 | 问题 |
|---|---|
| grep + cut | 如果日志格式变动,容易提取失败 |
| awk + 时间戳转换(mktime) | 依赖系统 locale,且复杂、易出错 |
| 仅用字符串匹配 PASS | 无法判断时间范围 |
当前写法 最稳健、最兼容、最不依赖环境。
textLATEST_SUCCESS_LOOP=$(awk -v start_time="$YESTERDAY_START" ' /PASS/ { # 提取时间戳 (格式: 2024-01-01 12:30:45) match($0, /[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/) if (RSTART > 0) { log_time = substr($0, RSTART, RLENGTH) if (log_time >= start_time) { count++ } } } END { print count+0 } ' ${RECORD_FILE})
我主要是这一段 不知道说什么 match awk 我不太会,最后为什么要加个 record_file?
这段其实就是:在日志文件 ${RECORD_FILE} 里,找出包含 PASS 的行;从每行里“抠”出时间戳;如果时间戳 ≥ 昨天 0 点,就把计数 +1;最后输出计数。
你卡住的点主要有两个:match() 是啥、最后为啥要加 ${RECORD_FILE}。
awk ... '程序' ${RECORD_FILE} 这一坨在干嘛?awk 的常见用法是:
bashawk '这里写处理规则' 文件名
'...' 里面写的是 awk 程序(怎么处理每一行)${RECORD_FILE} 是 输入数据来源(要处理哪个文件)如果你不写 ${RECORD_FILE},awk 就不知道去读哪个文件(除非你用管道给它喂输入,比如 cat file | awk '...',或者让它从标准输入等你手动输入)。
所以这句:
bashawk ... '...' ${RECORD_FILE}
等价于:“用 awk 逐行读取 ${RECORD_FILE},按引号里的规则处理”。
/PASS/ { ... } 是什么意思?在 awk 里:
awk/PASS/ { ... }
表示:只有当前这一行匹配正则 PASS(即行里包含 PASS)时,才执行花括号里的动作。
match($0, /.../) 是什么意思?match(字符串, 正则) 用来在“字符串里找符合正则的那一段”。
$0:awk 的内置变量,代表 当前整行文本/[0-9]{4}-.../:正则表达式,匹配类似 2024-01-01 12:30:45 的时间戳调用 match() 以后,awk 会设置两个内置变量:
RSTART:匹配到的子串从第几个字符开始(从 1 开始),找不到就是 0RLENGTH:匹配到的子串长度,找不到就是 -1所以这句:
awkmatch($0, /YYYY-MM-DD HH:MM:SS/)
意思是:在这一整行 $0 里找时间戳,如果找到了,就记下它的位置和长度。
if (RSTART > 0) { log_time = substr($0, RSTART, RLENGTH) }RSTART > 0:说明找到了时间戳substr($0, RSTART, RLENGTH):从整行 $0 里,把刚才 match 到的那段时间戳截出来举例:假设某一行是
INFO ... 2024-02-10 01:20:10 ... PASS loop: 60
match 找到时间戳后,substr(...) 就会得到:
log_time = "2024-02-10 01:20:10"
if (log_time >= start_time) { count++ } 为啥能这么比?因为时间格式是 YYYY-MM-DD HH:MM:SS,这个格式的字符串按字典序比较,恰好等价于时间先后比较。
比如:
"2024-02-10 01:00:00" >= "2024-02-10 00:00:00" ✅"2024-02-09 23:59:59" >= "2024-02-10 00:00:00" ❌所以:只要日志里的时间戳也是这个格式,就可以直接用字符串比较筛选“昨天0点之后”的 PASS。
END { print count+0 } 是干嘛的?为什么 +0?END { ... }:awk 把文件所有行都处理完后,再执行一次这里面的东西。
print count+0 有两个小目的:
count++,count 可能是空/未定义;+0 会把它变成 0${RECORD_FILE}?”因为 awk 必须知道 读哪个文件。你这段 awk 不是从管道输入来的,所以要在最后写文件名:
bash... 'awk程序' ${RECORD_FILE}
否则 awk 会等标准输入,脚本跑起来就会卡住(或读不到数据)。
如果你愿意,我也可以把这段 awk 改成更容易读的版本(比如直接让 awk 只处理“以时间开头的行”,或者在日志格式固定的情况下简化掉 match/substr),但不影响功能。