Bash关机脚本时间判断异常问题求助
初始问题
编写了一款Bash脚本,用于监控系统时间、执行指定任务,并在关机倒计时结束前1分钟通过Telegram发送通知。但遇到核心问题:当当前分钟为08及以上时,脚本的分钟判断IF条件无法触发。
已知Bash会将带前导零的数字识别为八进制数,尝试通过去除前导零转为十进制解决该问题,单独测试该逻辑有效,但放到主脚本中完全失效。
示例场景:设置10分钟后关机,当前时间为01:00:00,关机时间为01:10:00,脚本生成T01H10M.shutdown文件并从中提取小时和分钟,本该在01:09:00发送通知,但08分钟及以上时完全无反应。
初始代码片段:
# 从文件名中提取关机时间 SearchFilenameDateWhenPCgotoShutdown="$(find /root/ -name '*.shutdown')" SearchTimeHour=$(echo $SearchFilenameDateWhenPCgotoShutdown | cut -f2 -d "T"| cut -f1 -d "H") SearchTimeMinute=$(echo $SearchFilenameDateWhenPCgotoShutdown | cut -f2 -d "H" | cut -f1 -d "M") # 计算倒数第二分钟并修正减法错误 SearchTimeMinuteMinus1=$(($SearchTimeMinute - 1 )) if [ $SearchTimeMinuteMinus1 -eq -2 ]; then SearchTimeMinuteMinus1=58; fi if [ $SearchTimeMinuteMinus1 -eq -1 ]; then SearchTimeMinuteMinus1=59 fi # 获取当前小时和分钟 RealTimeHour=$(date "+%H") RealTimeMinute=$(date "+%M") if [ $RealTimeMinute = 00 ]; then RealTimeMinute=0; else RealTimeMinute=`echo $RealTimeMinute |sed 's/^0*//'` fi # 判断小时是否匹配 if [ $SearchTimeHour = $RealTimeHour ]; then if [ $SearchTimeMinuteMinus1 = $RealTimeMinute ]; then curl -s "https://api.telegram.org/xxx" &> /dev/null fi fi
更新后新问题
修改代码后脚本恢复正常,但当时间为59分钟时,小时判断的IF条件会触发错误,所有变量定义明明都是正确的。
完整更新代码:
#!/bin/bash if ping -c 2 100.100.100.100 | grep "ttl"; then if ping -c 2 192.168.10.1 | grep "ttl"; then if ping -c 2 192.168.88.102 | grep "ttl"; then # OMV名称 NameOMV="Standart OMV" # 关机倒计时分钟数 ShutDownParameterMinutes=2 # 标记文件路径 startmark=/root/startmark # 检查标记文件是否存在 if [ -f $startmark ] then # 获取关机时间文件 SearchFilenameDateWhenPCgotoShutdown="$(find /root/ -name '*.shutdown')" # 提取关机小时和分钟 SearchTimeHour=$(echo "$SearchFilenameDateWhenPCgotoShutdown" | cut -f2 -d "T"| cut -f1 -d "H") SearchTimeMinute=$(echo "$SearchFilenameDateWhenPCgotoShutdown" | cut -f2 -d "H" | cut -f1 -d "M") # 计算通知时间(关机前1分钟)并修正减法错误 SearchTimeMinuteMinus1=$((SearchTimeMinute - 1 )) if [ "$SearchTimeMinuteMinus1" -eq -2 ]; then SearchTimeMinuteMinus1=58 fi if [ "$SearchTimeMinuteMinus1" -eq -1 ]; then SearchTimeMinuteMinus1=59 fi curl -s "https://api.telegram.org/xxx&text=%F0%9F%93%B7 SearchTimeMinuteMinus1=${SearchTimeMinuteMinus1}" &> /dev/null # 获取当前小时和分钟 RealTimeHour=$(date "+%H") RealTimeMinute=$(date "+%M") RealTimeMinute=$((10#$RealTimeMinute)) curl -s "https://api.telegram.org/xxx&text=%F0%9F%93%B7 RealTimeHour=${RealTimeHour}" &> /dev/null curl -s "https://api.telegram.org/xxx&text=%F0%9F%93%B7 RealTimeMinute=${RealTimeMinute}" &> /dev/null curl -s "https://api.telegram.org/xxx&text=%F0%9F%93%B7 TICK $(date "%d.%m.%Y - %H:%M:%S")" &> /dev/null # 判断小时是否匹配 if [ "$SearchTimeHour" -eq "$RealTimeHour" ]; then curl -s "https://api.telegram.org/xxx&text=%F0%9F%93%B7 Hour OK" &> /dev/null if [ "$SearchTimeMinuteMinus1" -eq "$RealTimeMinute" ]; then curl -s "https://api.telegram.org/xxx&text=%F0%9F%93%B7 Minute OK" &> /dev/null rm "$SearchFilenameDateWhenPCgotoShutdown" rm startmark curl -s "https://api.telegram.org/xxx&text=%F0%9F%93%B7 $NameOMV 距离关机还有1分钟" &> /dev/null fi fi else # 创建标记文件 touch startmark # 记录日志并发送Telegram通知 echo "OrangePi 启动关机流程: $(date "%d.%m.%Y - %H:%M:%S")" >> shutdownlog.txt # 计算关机时间并生成对应文件 DateWhenPCgotoShutdown=$(date +"T""%H""H""%M""M" --date="$ShutDownParameterMinutes minute") TimeStampStartName="${DateWhenPCgotoShutdown}.shutdown" touch "$TimeStampStartName" chmod +x "$TimeStampStartName" # 发送关机时间通知 TelegramMessage="OrangePi $NameOMV 将于 $(date "%d.%m.%Y - %H:%M:%S" --date="$ShutDownParameterMinutes minute") 关机" echo "${TelegramMessage}" >> shutdownlog.txt curl -s "https://api.telegram.org/xxx&text=%F0%9F%93%B7 $TelegramMessage" &> /dev/null # /sbin/shutdown -h +$ShutDownParameterMinutes echo "SHUTDOWN" fi fi fi fi
问题分析与修复方案
初始问题根源
初始代码中仅对当前分钟做了去前导零处理,但从文件名提取的SearchTimeHour和SearchTimeMinute仍然是带前导零的字符串(比如01、10),在进行数值运算或比较时,Bash会将其识别为八进制数——而八进制中不存在8、9,所以当分钟为08、09时,运算直接报错,导致条件判断完全失效。
更新后59分钟时的问题根源
更新代码中用RealTimeMinute=$((10#$RealTimeMinute))强制将当前分钟转为十进制,但未处理跨小时/跨天的时间逻辑:比如关机时间为00:00,通知时间应为前一天的23:59,但代码中仅将分钟修正为59,小时仍保留为00,此时当前小时是23,00 -eq 23的判断必然失败,导致59分钟时无法触发通知。
完整修复方案
- 统一所有时间变量的十进制转换:从文件名提取的小时和分钟,同样用
10#前缀强制转为十进制,彻底规避八进制识别问题。 - 完善跨小时/跨天的时间计算:当分钟减1后变为负数时,不仅要将分钟设为
59,还要将小时减1;若小时减1后为负数(跨天场景),则将小时设为23。 - 优化文件查找逻辑:用通配符匹配代替
find,避免返回多个文件导致的变量值混乱。
修复后的核心代码片段:
# 提取关机小时和分钟并强制转为十进制 SearchTimeHour=$((10#$(echo "$SearchFilenameDateWhenPCgotoShutdown" | cut -f2 -d "T"| cut -f1 -d "H"))) SearchTimeMinute=$((10#$(echo "$SearchFilenameDateWhenPCgotoShutdown" | cut -f2 -d "H" | cut -f1 -d "M"))) # 计算通知时间(关机前1分钟),处理跨小时/跨天场景 SearchTimeMinuteMinus1=$((SearchTimeMinute - 1)) SearchTimeHourMinus1=$SearchTimeHour if [ $SearchTimeMinuteMinus1 -lt 0 ]; then SearchTimeMinuteMinus1=59 SearchTimeHourMinus1=$((SearchTimeHour - 1)) # 处理跨天情况 if [ $SearchTimeHourMinus1 -lt 0 ]; then SearchTimeHourMinus1=23 fi fi # 获取当前时间并强制转为十进制 RealTimeHour=$((10#$(date "+%H"))) RealTimeMinute=$((10#$(date "+%M"))) # 判断时间是否匹配 if [ "$SearchTimeHourMinus1" -eq "$RealTimeHour" ] && [ "$SearchTimeMinuteMinus1" -eq "$RealTimeMinute" ]; then rm "$SearchFilenameDateWhenPCgotoShutdown" rm startmark curl -s "https://api.telegram.org/xxx&text=%F0%9F%93%B7 $NameOMV 距离关机还有1分钟" &> /dev/null fi
额外优化建议
- 将Telegram API地址存为独立变量,方便后续修改维护。
- 增加多关机文件的冲突处理逻辑,避免
find返回多个文件导致的异常。 - 所有变量引用均加上双引号,避免空格等特殊字符引发的语法错误。
内容的提问来源于stack exchange,提问作者Mk51

