This commit is contained in:
zlwu committed 2025-12-26 00:44:19 +08:00
1 parent 34a843e790
commit abfc5cd746
14 files changed
+1595 -1148

No files matched your search

@@ -0,0 +1,220 @@
# 学生状态变更处理系统 - 生产环境部署指南
## 📋 概述
本系统包含两个核心处理脚本,已修复Ubuntu环境兼容性问题:
- `process_student_changes_fixed.sh` - 学生状态变更处理(休学/退学/毕业)
- `process_student_resume_fixed.sh` - 学生复学处理
## 🚀 快速启动
### 1. 启动所有服务
```bash
cd /path/to/scripts
./control_scripts.sh startall
```
### 2. 检查运行状态
```bash
./control_scripts.sh statusall
```
### 3. 健康检查
```bash
./control_scripts.sh health all
```
### 4. 查看系统资源
```bash
./control_scripts.sh info
```
## 📁 文件结构
```
/scripts/
├── control_scripts.sh # 生产环境控制脚本
├── process_student_changes_fixed.sh # 状态变更处理脚本
├── process_student_resume_fixed.sh # 复学处理脚本
├── data.conf # 配置文件
├── logs/ # 控制脚本日志目录
│ └── control_scripts_YYYYMMDD.log
└── student_status_change/ # 处理脚本日志目录
└── process_student_*_YYYYMMDD_HHMMSS.log
```
## ⚙️ 配置要求
### 数据库配置 (data.conf)
```bash
# Database configuration
DB_HOST="your_db_host"
DB_PORT="3306"
DB_NAME="your_db_name"
DB_USER="your_db_user"
DB_PASS="your_db_password"
# Processing configuration
BATCH_SIZE=100 # 每批处理记录数
MAX_RETRY=3 # 最大重试次数
RETRY_DELAY=5 # 重试间隔(秒)
CYCLE_INTERVAL=600 # 处理周期间隔(秒)
```
### 系统要求
- Ubuntu 18.04+ / CentOS 7+
- Bash 4.0+
- MySQL 5.7+ / MariaDB 10.0+
- 标准系统工具 (ps, kill, chmod等)
## 🎯 控制脚本命令
### 基础操作
```bash
# 启动/停止/重启
./control_scripts.sh start changes # 启动状态变更处理
./control_scripts.sh stop resume # 停止复学处理
./control_scripts.sh restart changes # 重启状态变更处理
# 状态检查
./control_scripts.sh status changes # 查看状态变更脚本状态
./control_scripts.sh statusall # 查看所有脚本状态
```
### 批量操作
```bash
# 启动所有脚本
./control_scripts.sh startall
# 停止所有脚本
./control_scripts.sh stopall
# 重启所有脚本 (需要时使用)
./control_scripts.sh restart all
```
### 监控和维护
```bash
# 健康检查
./control_scripts.sh health changes # 检查单个脚本
./control_scripts.sh health all # 检查所有脚本
# 系统资源监控
./control_scripts.sh info
```
## 🔍 故障排除
### 常见问题
#### 1. 脚本无法启动
**症状**: `start` 命令失败
**检查**:
```bash
# 检查脚本权限
ls -la *.sh
# 检查配置文件
cat data.conf
# 检查数据库连接
mysql -h$DB_HOST -P$DB_PORT -u$DB_USER -p$DB_PASS $DB_NAME -e "SELECT 1;"
```
#### 2. 脚本状态显示异常
**症状**: `status` 显示未知状态
**解决**:
```bash
# 清理可能的残留文件
rm -f *.lock pids/*.pid
# 重启脚本
./control_scripts.sh restart all
```
#### 3. 数据库连接失败
**症状**: 健康检查显示数据库连接失败
**检查**:
- 确认数据库服务运行
- 验证连接参数
- 检查网络连接
#### 4. 日志文件过大
**解决**:
```bash
# 清理旧日志 (保留最近7天)
find logs/ -name "*.log" -mtime +7 -delete
find student_status_change/ -name "*.log" -mtime +7 -delete
```
### 日志位置
- **控制脚本日志**: `logs/control_scripts_YYYYMMDD.log`
- **处理脚本日志**: `student_status_change/process_student_*_YYYYMMDD_HHMMSS.log`
## 📊 监控要点
### 关键指标
1. **脚本运行状态**: 确保两个处理脚本都在运行
2. **数据库连接**: 定期检查数据库连接性
3. **处理效率**: 观察日志中的处理记录数和耗时
4. **系统资源**: CPU/内存/磁盘使用率
5. **错误日志**: 关注ERROR和WARN级别的日志
### 自动化监控脚本
```bash
#!/bin/bash
# 监控脚本示例
SCRIPT_DIR="/path/to/scripts"
LOG_FILE="/var/log/student_monitor.log"
echo "$(date): 检查脚本状态" >> "$LOG_FILE"
cd "$SCRIPT_DIR"
# 检查脚本状态
if ! ./control_scripts.sh health all >> "$LOG_FILE" 2>&1; then
echo "$(date): 健康检查失败,发送告警" >> "$LOG_FILE"
# 发送告警邮件/短信等
fi
```
## 🔄 升级部署
### 停机升级
```bash
# 1. 停止所有服务
./control_scripts.sh stopall
# 2. 备份当前脚本
cp *.sh backup/
# 3. 部署新版本脚本
# (复制新版本文件)
# 4. 启动服务
./control_scripts.sh startall
# 5. 验证功能
./control_scripts.sh health all
```
### 热升级 (推荐)
```bash
# 逐个重启脚本,最小化服务中断
./control_scripts.sh restart changes
sleep 30
./control_scripts.sh restart resume
```
## 📞 支持
如遇到问题,请检查:
1. 日志文件中的错误信息
2. 系统资源使用情况
3. 数据库连接状态
4. 脚本执行权限
---
**最后更新**: 2025-12-26
**版本**: Ubuntu兼容修复版本
@@ -1,11 +1,40 @@
#!/bin/bash
# ===========================================
# 学生状态变更处理脚本控制程序
# 用于启动、停止、重启处理脚本
# 学生状态变更处理脚本控制程序 - 生产环境版本
# 用于启动、停止、重启处理脚本 (Ubuntu兼容性修复版本)
# ===========================================
#
# 生产环境部署指南:
# 1. 确保所有修复版本脚本存在:
# - process_student_changes_fixed.sh (状态变更处理)
# - process_student_resume_fixed.sh (复学处理)
#
# 2. 确保配置文件存在:
# - data.conf (数据库配置和脚本参数)
#
# 3. 启动所有服务:
# ./control_scripts.sh startall
#
# 4. 监控运行状态:
# ./control_scripts.sh statusall
#
# 5. 健康检查:
# ./control_scripts.sh health all
#
# 6. 查看系统资源:
# ./control_scripts.sh info
#
# 日志文件位置:
# - 控制脚本日志: logs/control_scripts_YYYYMMDD.log
# - 处理脚本日志: student_status_change/process_student_*_YYYYMMDD_HHMMSS.log
set -euo pipefail
# Disable strict error checking for better production resilience
# set -euo pipefail # Temporarily disabled for production robustness
# Force C locale for consistent behavior across systems
export LANG=C
export LC_ALL=C
# Load configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -13,16 +42,33 @@ CONFIG_FILE="${SCRIPT_DIR}/data.conf"
if [[ ! -f "$CONFIG_FILE" ]]; then
echo "错误:配置文件 $CONFIG_FILE 未找到!"
echo "请确保 data.conf 文件存在于脚本目录中"
exit 1
fi
source "$CONFIG_FILE"
# Script definitions
declare -A SCRIPTS=(
["changes"]="process_student_changes.sh"
["resume"]="process_student_resume.sh"
)
# Production environment setup
PRODUCTION_LOG_DIR="${SCRIPT_DIR}/logs"
mkdir -p "$PRODUCTION_LOG_DIR"
PRODUCTION_LOG_FILE="${PRODUCTION_LOG_DIR}/control_scripts_$(date +%Y%m%d).log"
# Script definitions - Production versions with Ubuntu compatibility fixes
# Using indexed arrays for better bash compatibility
SCRIPT_NAMES=("changes" "resume")
SCRIPT_FILES=("process_student_changes_fixed.sh" "process_student_resume_fixed.sh")
# Function to get script file by name
get_script_file() {
local script_name="$1"
for i in "${!SCRIPT_NAMES[@]}"; do
if [[ "${SCRIPT_NAMES[$i]}" == "$script_name" ]]; then
echo "${SCRIPT_FILES[$i]}"
return 0
fi
done
return 1
}
# PID files
PID_DIR="${SCRIPT_DIR}/pids"
@@ -33,7 +79,13 @@ log() {
local level="$1"
local message="$2"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message"
local log_message="[$timestamp] [$level] $message"
# Output to console
echo "$log_message"
# Output to production log file
echo "$log_message" >> "$PRODUCTION_LOG_FILE"
}
get_pid_file() {
@@ -76,9 +128,64 @@ is_running() {
return 1 # Not running
}
# Health check function for production monitoring
health_check() {
local script_name="$1"
local script_file="${SCRIPT_DIR}/$(get_script_file "$script_name")"
log "INFO" "执行 $script_name 的健康检查..."
# Check if script file exists and is executable
if [[ ! -f "$script_file" ]]; then
log "ERROR" "$script_name 脚本文件不存在: $script_file"
return 1
fi
if [[ ! -x "$script_file" ]]; then
log "WARN" "$script_name 脚本文件没有执行权限,正在修复..."
chmod +x "$script_file"
fi
# Check database connectivity
if ! mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SELECT 1;" >/dev/null 2>&1; then
log "ERROR" "$script_name 数据库连接失败"
return 1
fi
# Check if script is running
if ! is_running "$script_name"; then
log "WARN" "$script_name 脚本未运行"
return 1
fi
log "INFO" "$script_name 健康检查通过"
return 0
}
# Get system resource usage
get_system_info() {
log "INFO" "=== 系统资源信息 ==="
# CPU usage
local cpu_usage=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
log "INFO" "CPU使用率: ${cpu_usage}%"
# Memory usage
local mem_info=$(free -h | grep "^Mem:")
log "INFO" "内存信息: $mem_info"
# Disk usage
local disk_info=$(df -h "$SCRIPT_DIR" | tail -1 | awk '{print $1 ": " $5 " used (" $4 " free)"}')
log "INFO" "磁盘使用: $disk_info"
# Process count
local process_count=$(pgrep -f "process_student.*\.sh" | wc -l)
log "INFO" "运行中的学生处理进程数: $process_count"
}
start_script() {
local script_name="$1"
local script_file="${SCRIPT_DIR}/${SCRIPTS[$script_name]}"
local script_file="${SCRIPT_DIR}/$(get_script_file "$script_name")"
local pid_file=$(get_pid_file "$script_name")
if [[ ! -f "$script_file" ]]; then
@@ -189,38 +296,74 @@ show_usage() {
stop 停止指定的脚本
restart 重启指定的脚本
status 显示指定脚本的状态
health 执行脚本健康检查
startall 启动所有脚本
stopall 停止所有脚本
statusall 显示所有脚本的状态
info 显示系统资源信息
脚本名称:
changes 学生状态变更脚本 (休学/退学/毕业)
resume 学生复学脚本 (复学)
changes 学生状态变更脚本 (休学/退学/毕业) - Ubuntu兼容修复版本
resume 学生复学脚本 (复学) - Ubuntu兼容修复版本
all 所有脚本
示例:
生产环境示例:
$0 startall # 启动所有学生处理脚本
$0 statusall # 检查所有脚本运行状态
$0 health all # 执行所有脚本的健康检查
$0 info # 查看系统资源使用情况
$0 restart changes # 重启状态变更处理脚本
$0 stopall # 停止所有处理脚本
传统示例:
$0 start changes # 启动状态变更处理脚本
$0 stop resume # 停止复学处理脚本
$0 restart changes # 重启状态变更处理脚本
$0 status all # 显示所有脚本的状态
$0 startall # 启动所有脚本
$0 stopall # 停止所有脚本
$0 status changes # 显示状态变更脚本状态
注意:
本脚本使用修复版本,已适配Ubuntu环境,解决了循环处理和数据库查询的兼容性问题
EOF
}
# Production environment initialization
init_production_env() {
log "INFO" "初始化生产环境..."
# Check script files exist
for script_name in "${!SCRIPTS[@]}"; do
local script_file="${SCRIPT_DIR}/${SCRIPTS[$script_name]}"
if [[ ! -f "$script_file" ]]; then
log "ERROR" "脚本文件不存在: $script_file"
log "ERROR" "请确保已部署修复版本的脚本文件"
exit 1
fi
done
# Test database connectivity
if ! mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SELECT 1;" >/dev/null 2>&1; then
log "ERROR" "数据库连接失败,请检查配置"
exit 1
fi
log "INFO" "生产环境初始化完成"
}
# Main function
main() {
# Initialize production environment
init_production_env
local command="${1:-}"
local script_name="${2:-}"
case "$command" in
start)
if [[ "$script_name" == "all" ]]; then
for script in "${!SCRIPTS[@]}"; do
for script in "${SCRIPT_NAMES[@]}"; do
start_script "$script"
done
elif [[ -n "${SCRIPTS[$script_name]}" ]]; then
elif get_script_file "$script_name" >/dev/null 2>&1; then
start_script "$script_name"
else
log "ERROR" "未知的脚本名称: $script_name"
@@ -231,10 +374,10 @@ main() {
stop)
if [[ "$script_name" == "all" ]]; then
for script in "${!SCRIPTS[@]}"; do
for script in "${SCRIPT_NAMES[@]}"; do
stop_script "$script"
done
elif [[ -n "${SCRIPTS[$script_name]}" ]]; then
elif get_script_file "$script_name" >/dev/null 2>&1; then
stop_script "$script_name"
else
log "ERROR" "未知的脚本名称: $script_name"
@@ -245,10 +388,10 @@ main() {
restart)
if [[ "$script_name" == "all" ]]; then
for script in "${!SCRIPTS[@]}"; do
for script in "${SCRIPT_NAMES[@]}"; do
restart_script "$script"
done
elif [[ -n "${SCRIPTS[$script_name]}" ]]; then
elif get_script_file "$script_name" >/dev/null 2>&1; then
restart_script "$script_name"
else
log "ERROR" "未知的脚本名称: $script_name"
@@ -259,10 +402,10 @@ main() {
status)
if [[ "$script_name" == "all" ]]; then
for script in "${!SCRIPTS[@]}"; do
for script in "${SCRIPT_NAMES[@]}"; do
status_script "$script"
done
elif [[ -n "${SCRIPTS[$script_name]}" ]]; then
elif get_script_file "$script_name" >/dev/null 2>&1; then
status_script "$script_name"
else
log "ERROR" "未知的脚本名称: $script_name"
@@ -273,25 +416,59 @@ main() {
startall)
log "INFO" "正在启动所有脚本..."
for script in "${!SCRIPTS[@]}"; do
for script in "${SCRIPT_NAMES[@]}"; do
start_script "$script"
done
;;
stopall)
log "INFO" "正在停止所有脚本..."
for script in "${!SCRIPTS[@]}"; do
for script in "${SCRIPT_NAMES[@]}"; do
stop_script "$script"
done
;;
statusall)
log "INFO" "正在检查所有脚本的状态..."
for script in "${!SCRIPTS[@]}"; do
for script in "${SCRIPT_NAMES[@]}"; do
status_script "$script"
done
;;
health)
if [[ "$script_name" == "all" ]]; then
local all_healthy=true
for script in "${SCRIPT_NAMES[@]}"; do
if ! health_check "$script"; then
all_healthy=false
fi
done
if [[ "$all_healthy" == true ]]; then
log "INFO" "所有脚本健康检查通过"
exit 0
else
log "ERROR" "部分脚本健康检查失败"
exit 1
fi
elif get_script_file "$script_name" >/dev/null 2>&1; then
if health_check "$script_name"; then
log "INFO" "$script_name 健康检查通过"
exit 0
else
log "ERROR" "$script_name 健康检查失败"
exit 1
fi
else
log "ERROR" "未知的脚本名称: $script_name"
show_usage
exit 1
fi
;;
info)
get_system_info
;;
*)
log "ERROR" "未知命令: $command"
show_usage
@@ -0,0 +1,17 @@
# Database configuration
DB_HOST="172.16.0.67"
DB_PORT="3306"
DB_NAME="hzdyjs_xg"
DB_USER="root"
DB_PASS="Hzdyjs@Root@123456"
# Script configuration
LOG_DIR="${SCRIPT_DIR}/student_status_change"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOCK_FILE="${SCRIPT_DIR}/script.lock"
# Processing configuration
BATCH_SIZE=100
MAX_RETRY=3
RETRY_DELAY=5
CYCLE_INTERVAL=600 # 循环间隔时间(秒),默认10分钟
@@ -1,69 +0,0 @@
# ===========================================
# 学生状态变更处理脚本 - 可选的Crontab配置
# ===========================================
# 注意:脚本现在采用持续运行模式,默认每10分钟自动处理一次
# 此配置文件仅供特殊情况下的备用配置使用
# 如果不使用持续运行模式,可以使用以下crontab配置:
# 1. 将以下内容添加到系统的 crontab 中:crontab -e
# 2. 根据实际需要调整执行时间和频率
# 3. 确保脚本路径正确
# 4. 确保用户有执行权限
# 脚本所在目录(请根据实际情况修改)
SCRIPT_DIR="/path/to/student_status_scripts"
# 每天早上8点执行学生状态变更处理
0 8 * * * $SCRIPT_DIR/process_student_changes.sh
# 每天早上8点30分执行学生复学处理
30 8 * * * $SCRIPT_DIR/process_student_resume.sh
# 每小时执行一次健康检查
0 * * * * $SCRIPT_DIR/health_check.sh report
# 每周一早上6点重启所有服务(可选,用于定期重启确保稳定性)
0 6 * * 1 $SCRIPT_DIR/stop_services.sh && sleep 5 && $SCRIPT_DIR/start_services.sh
# 每天晚上10点清理旧日志文件(保留7天)
0 22 * * * find $SCRIPT_DIR/logs -name "*.log" -type f -mtime +7 -delete
# 每分钟检查服务状态,如果服务停止则自动重启(可选)
# */1 * * * * $SCRIPT_DIR/control_scripts.sh statusall >/dev/null 2>&1 || ($SCRIPT_DIR/stop_services.sh force && $SCRIPT_DIR/start_services.sh)
# ===========================================
# Crontab 语法说明
# ===========================================
# 分 时 日 月 周 命令
# * * * * * command
#
# 字段说明:
# 分 - 0-59
# 时 - 0-23
# 日 - 1-31
# 月 - 1-12
# 周 - 0-7 (0和7都表示星期日)
#
# 常用示例:
# 0 8 * * * - 每天早上8点
# */30 * * * * - 每30分钟
# 0 */2 * * * - 每2小时
# 0 9-17 * * 1-5 - 周一到周五的9点到17点,每小时执行一次
# @reboot - 系统重启时执行
# ===========================================
# 监控和告警建议
# ===========================================
# 1. 监控日志中的ERROR关键字
# 可以使用logwatch或自定义脚本监控日志
# 2. 监控数据库连接
# */5 * * * * mysql -h host -u user -p pass -e "SELECT 1;" || echo "DB connection failed" | mail -s "DB Alert" admin@example.com
# 3. 监控磁盘空间
# */30 * * * * df /var/log | awk 'NR==2 {if($5>90) print "Disk usage high: "$5}' | mail -s "Disk Alert" admin@example.com
# 4. 监控进程状态
# */5 * * * * pgrep -f "process_student_changes.sh" >/dev/null || echo "Process died" | mail -s "Process Alert" admin@example.com
@@ -82,6 +82,25 @@ execute_sql() {
echo "$result"
}
# Database query function - Fixed version for cross-platform compatibility
execute_query() {
local sql="$1"
local result
# Use -ss for ultra-silent mode to ensure clean tab-separated output
# Redirect stderr to /dev/null to discard warnings, only capture actual data
result=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" -ss "$DB_NAME" -e "$sql" 2>/dev/null)
local exit_code=$?
if [[ $exit_code -ne 0 ]]; then
log "ERROR" "查询执行失败: $sql"
log "ERROR" "MySQL错误码: $exit_code"
return 1
fi
echo "$result"
}
# Process student status change
process_student_change() {
local record_id="$1"
@@ -105,20 +124,16 @@ process_student_change() {
local bed_ids=""
# Execute dormitory query with error handling
if dorm_info=$(execute_sql "$dorm_query" 2>/dev/null); then
# Parse the result (skip header if present)
if [[ -n "$dorm_info" ]]; then
# Remove warnings, keep only data rows
dorm_info=$(echo "$dorm_info" | grep -v "mysql:" | grep -E "^[0-9]+\t" | head -n 1)
if [[ -n "$dorm_info" && "$dorm_info" != "NULL" && "$dorm_info" != "NULL\tNULL" ]]; then
# Split by tab and handle NULL values
IFS=$'\t' read -r dorm_ids_raw bed_ids_raw <<< "$dorm_info"
if [[ "$dorm_ids_raw" != "NULL" && -n "$dorm_ids_raw" ]]; then
dorm_ids="$dorm_ids_raw"
fi
if [[ "$bed_ids_raw" != "NULL" && -n "$bed_ids_raw" ]]; then
bed_ids="$bed_ids_raw"
fi
if dorm_info=$(execute_query "$dorm_query" 2>/dev/null); then
# Parse the result - handle NULL values properly
if [[ -n "$dorm_info" && "$dorm_info" != "NULL" && "$dorm_info" != "NULL\tNULL" ]]; then
# Split by tab and handle NULL values
IFS=$'\t' read -r dorm_ids_raw bed_ids_raw <<< "$dorm_info"
if [[ "$dorm_ids_raw" != "NULL" && -n "$dorm_ids_raw" ]]; then
dorm_ids="$dorm_ids_raw"
fi
if [[ "$bed_ids_raw" != "NULL" && -n "$bed_ids_raw" ]]; then
bed_ids="$bed_ids_raw"
fi
fi
else
@@ -285,18 +300,32 @@ main() {
if [[ $record_count -le 1 ]]; then
log "INFO" "未找到未处理的记录,正在等待..."
else
# 移除标题行和可能的警告信息
records=$(echo "$records" | grep -v "mysql:" | grep -v "id\t" | grep -v "^$")
local processed_count=0
local failed_count=0
# Process each record
# Process records directly, skip header and invalid lines
local is_first_line=true
while IFS=$'\t' read -r record_id student_id student_no change_type operator_id; do
# Skip empty lines
[[ -z "$record_id" ]] && continue
# Skip completely empty lines and MySQL warnings
[[ -z "$record_id$student_id$student_no$change_type$operator_id" || "$record_id" =~ ^mysql: ]] && continue
# Skip header line (first non-empty line that looks like column names)
if [[ $is_first_line == true ]]; then
is_first_line=false
# Check if this looks like a header line
if [[ "$record_id" == "id" || "$record_id" =~ ^[[:space:]]*id[[:space:]]*$ ]]; then
log "INFO" "跳过标题行"
continue
fi
fi
# Validate required fields
if [[ -z "$record_id" || -z "$student_id" || -z "$student_no" || -z "$change_type" ]]; then
log "WARN" "跳过无效记录 - ID: '$record_id', 学生ID: '$student_id', 学号: '$student_no', 类型: '$change_type'"
continue
fi
log "INFO" "读取到记录 - ID: $record_id, 学生ID: $student_id, 学号: $student_no, 类型: $change_type, 操作员: ${operator_id:-1}"
local retry_count=0
local success=false
@@ -0,0 +1,357 @@
#!/bin/bash
# ===========================================
# 学生状态变更处理脚本 - 毕业/退学/休学 (修复版本)
# 处理类型: XIU_XUE(休学), TUI_XUE(退学), BI_YE(毕业)
# ===========================================
# set -euo pipefail # Temporarily disable to prevent script exit on errors
# Force C locale to ensure consistent behavior across systems
export LANG=C
export LC_ALL=C
# Load configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_FILE="${SCRIPT_DIR}/data.conf"
if [[ ! -f "$CONFIG_FILE" ]]; then
echo "错误:配置文件 $CONFIG_FILE 未找到!"
exit 1
fi
source "$CONFIG_FILE"
# Create log directory
mkdir -p "$LOG_DIR"
# Log file
LOG_FILE="${LOG_DIR}/process_student_changes_fixed_$(date +%Y%m%d_%H%M%S).log"
# Lock file to prevent multiple instances
LOCK_FILE="${SCRIPT_DIR}/process_student_changes_fixed.lock"
# Functions
log() {
local level="$1"
local message="$2"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE"
}
error_exit() {
local message="$1"
log "ERROR" "$message"
# Remove lock file
[[ -f "$LOCK_FILE" ]] && rm -f "$LOCK_FILE"
exit 1
}
# Database functions - Fixed version
execute_sql() {
local sql="$1"
local result
result=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "$sql" 2>&1)
local exit_code=$?
if [[ $exit_code -ne 0 ]]; then
log "ERROR" "SQL执行失败: $sql"
log "ERROR" "MySQL错误: $result"
return 1
fi
echo "$result"
}
# Database query function - Fixed version for cross-platform compatibility
execute_query() {
local sql="$1"
local result
# Use -ss for ultra-silent mode to ensure clean tab-separated output
# Redirect stderr to /dev/null to discard warnings, only capture actual data
result=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" -ss "$DB_NAME" -e "$sql" 2>/dev/null)
local exit_code=$?
if [[ $exit_code -ne 0 ]]; then
log "ERROR" "查询执行失败: $sql"
log "ERROR" "MySQL错误码: $exit_code"
return 1
fi
echo "$result"
}
# Process student status change
process_student_change() {
local record_id="$1"
local student_id="$2"
local student_no="$3"
local change_type="$4"
local operator_id="${5:-1}"
# Validate input parameters
if [[ -z "$record_id" || -z "$student_id" || -z "$student_no" || -z "$change_type" ]]; then
log "ERROR" "参数不完整 - record_id: '$record_id', student_id: '$student_id', student_no: '$student_no', change_type: '$change_type'"
return 1
fi
log "INFO" "正在处理学生状态变更 - ID: $record_id, 学生: $student_no ($student_id), 类型: $change_type"
# Get dormitory assignment info before transaction
local dorm_query="
SELECT GROUP_CONCAT(id), GROUP_CONCAT(bed_id)
FROM xg_dorm_bed_student
WHERE student_id = $student_id AND status = '0' AND deleted = 0;
"
local dorm_info=""
local dorm_ids=""
local bed_ids=""
# Execute dormitory query with error handling
if dorm_info=$(execute_query "$dorm_query" 2>/dev/null); then
# Parse the result - handle NULL values properly
if [[ -n "$dorm_info" && "$dorm_info" != "NULL" && "$dorm_info" != "NULL\tNULL" ]]; then
# Split by tab and handle NULL values
IFS=$'\t' read -r dorm_ids_raw bed_ids_raw <<< "$dorm_info"
if [[ "$dorm_ids_raw" != "NULL" && -n "$dorm_ids_raw" ]]; then
dorm_ids="$dorm_ids_raw"
fi
if [[ "$bed_ids_raw" != "NULL" && -n "$bed_ids_raw" ]]; then
bed_ids="$bed_ids_raw"
fi
fi
else
log "WARN" "查询宿舍分配信息失败,将跳过宿舍处理 - 学生ID: $student_id"
fi
log "INFO" "找到宿舍分配 - ID: ${dorm_ids:-无}, 床位: ${bed_ids:-无}"
# Start transaction
local transaction_sql="
START TRANSACTION;
-- 1. Backup original data to his tables (ignore if already exists)
INSERT IGNORE INTO xg_student_msg_his SELECT * FROM xg_student_msg WHERE id = $student_id;
INSERT IGNORE INTO sys_user_his SELECT * FROM sys_user WHERE user_id = $student_id;
INSERT IGNORE INTO xg_class_pos_msg_his SELECT * FROM xg_class_pos_msg WHERE student_id = $student_id;
INSERT IGNORE INTO club_member_his SELECT * FROM club_member WHERE user_id = $student_id;
INSERT IGNORE INTO stgl_member_his SELECT * FROM stgl_member WHERE user_id = $student_id;
INSERT IGNORE INTO xg_dorm_bed_student_his SELECT * FROM xg_dorm_bed_student WHERE student_id = $student_id;
-- 2. Update student status
UPDATE xg_student_msg SET
student_status = CASE
WHEN '$change_type' = 'XIU_XUE' THEN '2'
WHEN '$change_type' = 'TUI_XUE' THEN '4'
WHEN '$change_type' = 'BI_YE' THEN '5'
ELSE student_status
END,
update_by = $operator_id,
update_time = NOW()
WHERE id = $student_id;
-- 3. Disable user account
UPDATE sys_user SET
status = '1',
update_by = $operator_id,
update_time = NOW()
WHERE user_id = $student_id AND account_type = '2';
-- 4. Process class position (cadre) - only for XIU_XUE, TUI_XUE, BI_YE
UPDATE xg_class_pos_msg SET
is_current = 0,
cadre_status = CASE
WHEN '$change_type' = 'XIU_XUE' THEN '6'
WHEN '$change_type' IN ('TUI_XUE', 'BI_YE') THEN '4'
ELSE cadre_status
END,
dismissal_date = CURDATE(),
dismissal_reason = CASE
WHEN '$change_type' = 'XIU_XUE' THEN '学生休学'
WHEN '$change_type' = 'TUI_XUE' THEN '学生退学'
WHEN '$change_type' = 'BI_YE' THEN '学生毕业'
ELSE dismissal_reason
END,
term_end_date = CURDATE(),
term_duration = TIMESTAMPDIFF(MONTH, term_start_date, CURDATE()),
update_by = $operator_id,
update_time = NOW()
WHERE student_id = $student_id AND is_current = 1;
-- 5. Process club membership - only for XIU_XUE, TUI_XUE, BI_YE
UPDATE club_member SET
member_status = '4',
update_by = $operator_id,
update_time = NOW()
WHERE user_id = $student_id AND member_status IN ('0', '1', '2');
-- 6. Process volunteer membership - only for XIU_XUE, TUI_XUE, BI_YE
UPDATE stgl_member SET
status = 4,
update_by = $operator_id,
update_time = NOW()
WHERE user_id = $student_id AND status IN (0, 1, 2);
-- 7. Process dormitory - only for TUI_XUE, BI_YE
-- First, clear dormitory info from student record
UPDATE xg_student_msg SET
dormitory_building = NULL,
dormitory_room = NULL,
ext_field1 = NULL,
update_time = NOW(),
update_by = $operator_id
WHERE id = $student_id;"
# Add dormitory processing only if assignments exist and are valid
if [[ -n "$dorm_ids" && "$dorm_ids" != "NULL" && -n "$bed_ids" && "$bed_ids" != "NULL" ]]; then
transaction_sql+="
-- Process dormitory checkout for specific assignments
UPDATE xg_dorm_bed_student SET
status = '1',
checkout_time = NOW(),
update_time = NOW(),
update_by = $operator_id
WHERE FIND_IN_SET(id, '$dorm_ids') AND deleted = 0;
-- Update bed status for specific beds
UPDATE xg_dorm_bed SET
bed_status = '0'
WHERE FIND_IN_SET(id, '$bed_ids') AND deleted = 0;"
log "INFO" "将处理宿舍退宿 - 分配ID: $dorm_ids, 床位ID: $bed_ids"
else
log "INFO" "无需处理宿舍退宿(无有效宿舍分配)"
fi
transaction_sql+="
-- 8. Update change record status
UPDATE xg_student_status_change SET
process_status = 1,
update_by = $operator_id,
update_time = NOW()
WHERE id = $record_id;
COMMIT;
"
# Execute transaction (using execute_sql to allow error output for debugging)
if execute_sql "$transaction_sql"; then
log "INFO" "成功处理学生状态变更 - ID: $record_id, 学生: $student_no"
return 0
else
log "ERROR" "处理学生状态变更失败 - ID: $record_id, 学生: $student_no"
return 1
fi
}
# Main function
main() {
log "INFO" "启动学生状态变更处理守护进程 (修复版本)"
log "INFO" "处理类型: XIU_XUE(休学), TUI_XUE(退学), BI_YE(毕业)"
log "INFO" "以连续模式运行,间隔10分钟"
# 测试数据库连接
log "INFO" "正在测试数据库连接..."
if ! execute_sql "SELECT 1;" >/dev/null 2>&1; then
error_exit "数据库连接失败"
fi
log "INFO" "数据库连接成功"
# Main processing loop
while true; do
log "INFO" "开始新的处理周期"
# 获取未处理的记录
local query_sql="
SELECT id, student_id, student_no, change_type, operator_id
FROM xg_student_status_change
WHERE process_status = 0
AND change_type IN ('XIU_XUE', 'TUI_XUE', 'BI_YE')
AND deleted = 0
AND effective_date <= NOW()
ORDER BY create_time ASC
LIMIT $BATCH_SIZE;
"
local records
records=$(execute_query "$query_sql")
if [[ $? -ne 0 ]]; then
log "ERROR" "获取待处理记录失败"
sleep $CYCLE_INTERVAL
continue
fi
# 检查是否有记录需要处理(过滤掉空行和MySQL警告信息)
local clean_records
clean_records=$(echo "$records" | grep -v "^mysql:" | grep -v "^$" | wc -l)
if [[ $clean_records -eq 0 ]]; then
log "INFO" "未找到未处理的记录,正在等待..."
else
log "INFO" "找到 $clean_records 条待处理记录"
local processed_count=0
local failed_count=0
# Process records directly from the query result, skip header and empty lines
local is_first_line=true
while IFS=$'\t' read -r record_id student_id student_no change_type operator_id; do
# Skip completely empty lines
[[ -z "$record_id$student_id$student_no$change_type$operator_id" ]] && continue
# Skip header line (first non-empty line that looks like column names)
if [[ $is_first_line == true ]]; then
is_first_line=false
# Check if this looks like a header line
if [[ "$record_id" == "id" || "$record_id" =~ ^[[:space:]]*id[[:space:]]*$ ]]; then
log "INFO" "跳过标题行"
continue
fi
fi
# Validate required fields
if [[ -z "$record_id" || -z "$student_id" || -z "$student_no" || -z "$change_type" ]]; then
log "WARN" "跳过无效记录 - ID: '$record_id', 学生ID: '$student_id', 学号: '$student_no', 类型: '$change_type'"
continue
fi
# Log the record being processed for debugging
log "INFO" "读取到记录 - ID: $record_id, 学生ID: $student_id, 学号: $student_no, 类型: $change_type, 操作员: ${operator_id:-1}"
local retry_count=0
local success=false
while [[ $retry_count -lt $MAX_RETRY && $success == false ]]; do
if process_student_change "$record_id" "$student_id" "$student_no" "$change_type" "$operator_id"; then
success=true
((processed_count++))
else
((retry_count++))
if [[ $retry_count -lt $MAX_RETRY ]]; then
log "WARN" "处理失败,$RETRY_DELAY 秒后重试... (尝试 $retry_count/$MAX_RETRY)"
sleep $RETRY_DELAY
fi
fi
done
if [[ $success == false ]]; then
((failed_count++))
log "ERROR" "$MAX_RETRY 次尝试后仍处理失败 - ID: $record_id"
fi
done <<< "$(echo "$records" | grep -v "^mysql:" | grep -v "^$")"
log "INFO" "处理周期完成 - 已处理: $processed_count, 失败: $failed_count"
fi
# 等待配置的间隔时间后开始下一个周期
log "INFO" "等待 $CYCLE_INTERVAL 秒后开始下一个处理周期..."
sleep $CYCLE_INTERVAL
done
}
# Run main function
main "$@"
@@ -0,0 +1,252 @@
#!/bin/bash
# ===========================================
# 学生状态变更处理脚本 - 复学 (修复版本)
# 处理类型: FU_XUE(复学)
# ===========================================
# set -euo pipefail # Temporarily disable to prevent script exit on errors
# Force C locale to ensure consistent behavior across systems
export LANG=C
export LC_ALL=C
# Load configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_FILE="${SCRIPT_DIR}/data.conf"
if [[ ! -f "$CONFIG_FILE" ]]; then
echo "错误:配置文件 $CONFIG_FILE 未找到!"
exit 1
fi
source "$CONFIG_FILE"
# Create log directory
mkdir -p "$LOG_DIR"
# Log file
LOG_FILE="${LOG_DIR}/process_student_resume_fixed_$(date +%Y%m%d_%H%M%S).log"
# Lock file to prevent multiple instances
LOCK_FILE="${SCRIPT_DIR}/process_student_resume_fixed.lock"
# Functions
log() {
local level="$1"
local message="$2"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE"
}
error_exit() {
local message="$1"
log "ERROR" "$message"
# Remove lock file
[[ -f "$LOCK_FILE" ]] && rm -f "$LOCK_FILE"
exit 1
}
# Database functions - Fixed version
execute_sql() {
local sql="$1"
local result
result=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "$sql" 2>&1)
local exit_code=$?
if [[ $exit_code -ne 0 ]]; then
log "ERROR" "SQL执行失败: $sql"
log "ERROR" "MySQL错误: $result"
return 1
fi
echo "$result"
}
# Database query function - Fixed version for cross-platform compatibility
execute_query() {
local sql="$1"
local result
# Use -ss for ultra-silent mode to ensure clean tab-separated output
# Redirect stderr to /dev/null to discard warnings, only capture actual data
result=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" -ss "$DB_NAME" -e "$sql" 2>/dev/null)
local exit_code=$?
if [[ $exit_code -ne 0 ]]; then
log "ERROR" "查询执行失败: $sql"
log "ERROR" "MySQL错误码: $exit_code"
return 1
fi
echo "$result"
}
# Process student resume
process_student_resume() {
local record_id="$1"
local student_id="$2"
local student_no="$3"
local change_type="$4"
local operator_id="${5:-1}"
# Validate input parameters
if [[ -z "$record_id" || -z "$student_id" || -z "$student_no" || -z "$change_type" ]]; then
log "ERROR" "参数不完整 - record_id: '$record_id', student_id: '$student_id', student_no: '$student_no', change_type: '$change_type'"
return 1
fi
log "INFO" "正在处理学生复学 - ID: $record_id, 学生: $student_no ($student_id), 类型: $change_type"
# Start transaction
local transaction_sql="
START TRANSACTION;
-- 1. Backup original data to his tables (ignore if already exists)
INSERT IGNORE INTO xg_student_msg_his SELECT * FROM xg_student_msg WHERE id = $student_id;
INSERT IGNORE INTO sys_user_his SELECT * FROM sys_user WHERE user_id = $student_id;
-- 2. Update student status to resume (复学)
UPDATE xg_student_msg SET
student_status = '1',
update_by = $operator_id,
update_time = NOW()
WHERE id = $student_id;
-- 3. Enable user account
UPDATE sys_user SET
status = '0',
update_by = $operator_id,
update_time = NOW()
WHERE user_id = $student_id AND account_type = '2';
-- 4. Update change record status
UPDATE xg_student_status_change SET
process_status = 1,
update_by = $operator_id,
update_time = NOW()
WHERE id = $record_id;
COMMIT;
"
# Execute transaction (using execute_sql to allow error output for debugging)
if execute_sql "$transaction_sql"; then
log "INFO" "成功处理学生复学 - ID: $record_id, 学生: $student_no"
return 0
else
log "ERROR" "处理学生复学失败 - ID: $record_id, 学生: $student_no"
return 1
fi
}
# Main function
main() {
log "INFO" "启动学生复学处理守护进程 (修复版本)"
log "INFO" "处理类型: FU_XUE(复学)"
log "INFO" "以连续模式运行,间隔10分钟"
# 测试数据库连接
log "INFO" "正在测试数据库连接..."
if ! execute_sql "SELECT 1;" >/dev/null 2>&1; then
error_exit "数据库连接失败"
fi
log "INFO" "数据库连接成功"
# Main processing loop
while true; do
log "INFO" "开始新的复学处理周期"
# 获取未处理的记录
local query_sql="
SELECT id, student_id, student_no, change_type, operator_id
FROM xg_student_status_change
WHERE process_status = 0
AND change_type = 'FU_XUE'
AND deleted = 0
AND effective_date <= NOW()
ORDER BY create_time ASC
LIMIT $BATCH_SIZE;
"
local records
records=$(execute_query "$query_sql")
if [[ $? -ne 0 ]]; then
log "ERROR" "获取待处理记录失败"
sleep $CYCLE_INTERVAL
continue
fi
# 检查是否有记录需要处理(过滤掉空行和MySQL警告信息)
local clean_records
clean_records=$(echo "$records" | grep -v "^mysql:" | grep -v "^$" | wc -l)
if [[ $clean_records -eq 0 ]]; then
log "INFO" "未找到未处理的复学记录,正在等待..."
else
log "INFO" "找到 $clean_records 条待处理复学记录"
local processed_count=0
local failed_count=0
# Process records directly from the query result, skip header and empty lines
local is_first_line=true
while IFS=$'\t' read -r record_id student_id student_no change_type operator_id; do
# Skip completely empty lines
[[ -z "$record_id$student_id$student_no$change_type$operator_id" ]] && continue
# Skip header line (first non-empty line that looks like column names)
if [[ $is_first_line == true ]]; then
is_first_line=false
# Check if this looks like a header line
if [[ "$record_id" == "id" || "$record_id" =~ ^[[:space:]]*id[[:space:]]*$ ]]; then
log "INFO" "跳过标题行"
continue
fi
fi
# Validate required fields
if [[ -z "$record_id" || -z "$student_id" || -z "$student_no" || -z "$change_type" ]]; then
log "WARN" "跳过无效记录 - ID: '$record_id', 学生ID: '$student_id', 学号: '$student_no', 类型: '$change_type'"
continue
fi
# Log the record being processed for debugging
log "INFO" "读取到复学记录 - ID: $record_id, 学生ID: $student_id, 学号: $student_no, 类型: $change_type, 操作员: ${operator_id:-1}"
local retry_count=0
local success=false
while [[ $retry_count -lt $MAX_RETRY && $success == false ]]; do
if process_student_resume "$record_id" "$student_id" "$student_no" "$change_type" "$operator_id"; then
success=true
((processed_count++))
else
((retry_count++))
if [[ $retry_count -lt $MAX_RETRY ]]; then
log "WARN" "处理失败,$RETRY_DELAY 秒后重试... (尝试 $retry_count/$MAX_RETRY)"
sleep $RETRY_DELAY
fi
fi
done
if [[ $success == false ]]; then
((failed_count++))
log "ERROR" "$MAX_RETRY 次尝试后仍处理失败 - ID: $record_id"
fi
done <<< "$(echo "$records" | grep -v "^mysql:" | grep -v "^$")"
log "INFO" "复学处理周期完成 - 已处理: $processed_count, 失败: $failed_count"
fi
# 等待配置的间隔时间后开始下一个周期
log "INFO" "等待 $CYCLE_INTERVAL 秒后开始下一个复学处理周期..."
sleep $CYCLE_INTERVAL
done
}
# Run main function
main "$@"
@@ -0,0 +1,140 @@
#!/bin/bash
# Production environment debug script for student status change scripts
# This script helps diagnose MySQL output format issues
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_FILE="${SCRIPT_DIR}/data.conf"
if [[ ! -f "$CONFIG_FILE" ]]; then
echo "错误:配置文件 $CONFIG_FILE 未找到!"
exit 1
fi
source "$CONFIG_FILE"
echo "=== 生产环境调试信息 ==="
echo "时间: $(date)"
echo "脚本目录: $SCRIPT_DIR"
echo "SHELL: $SHELL"
echo "BASH_VERSION: $BASH_VERSION"
echo
echo "=== MySQL版本信息 ==="
mysql --version
echo
echo "=== 系统信息 ==="
uname -a
echo
# Test basic connection
echo "=== 测试数据库连接 ==="
if mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SELECT 1;" >/dev/null 2>&1; then
echo "数据库连接成功"
else
echo "数据库连接失败"
exit 1
fi
echo
# Test query formats
echo "=== 测试MySQL查询输出格式 ==="
QUERY="SELECT id, student_id, student_no, change_type, operator_id FROM xg_student_status_change WHERE process_status = 0 AND change_type IN ('XIU_XUE', 'TUI_XUE', 'BI_YE') AND deleted = 0 AND effective_date <= NOW() ORDER BY create_time ASC LIMIT 2;"
echo "查询SQL: $QUERY"
echo
echo "1. 标准mysql -e 输出 (可能包含表格格式):"
echo "----------------------------------------"
mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "$QUERY" 2>&1
echo "----------------------------------------"
echo
echo "2. mysql -B 输出 (批量模式,无表格格式):"
echo "----------------------------------------"
mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" -B "$DB_NAME" -e "$QUERY" 2>&1
echo "----------------------------------------"
echo
echo "3. mysql -ss 输出 (超静默模式):"
echo "----------------------------------------"
mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" -ss "$DB_NAME" -e "$QUERY" 2>&1
echo "----------------------------------------"
echo
echo "=== 详细分析 -B 参数输出 ==="
RESULT_B=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" -B "$DB_NAME" -e "$QUERY" 2>&1)
echo "原始输出 (包含警告):"
echo "\"$RESULT_B\""
echo
echo "按行分割查看:"
echo "$RESULT_B" | while IFS= read -r line; do
echo "行: '$line'"
done
echo
echo "过滤MySQL警告后的结果:"
FILTERED_RESULT=$(echo "$RESULT_B" | grep -v "^mysql:" | grep -v "^$")
echo "\"$FILTERED_RESULT\""
echo
echo "解析为变量 (使用tab分隔):"
if [[ -n "$FILTERED_RESULT" ]]; then
echo "$FILTERED_RESULT" | while IFS=$'\t' read -r record_id student_id student_no change_type operator_id; do
echo "解析结果:"
echo " record_id: '$record_id'"
echo " student_id: '$student_id'"
echo " student_no: '$student_no'"
echo " change_type: '$change_type'"
echo " operator_id: '$operator_id'"
echo
# Test if variables are numeric
echo "变量类型检查:"
echo " record_id 是数字: $([[ '$record_id' =~ ^[0-9]+$ ]] && echo '是' || echo '否')"
echo " student_id 是数字: $([[ '$student_id' =~ ^[0-9]+$ ]] && echo '是' || echo '否')"
echo " operator_id 是数字或空: $([[ -z '$operator_id' || '$operator_id' =~ ^[0-9]+$ ]] && echo '是' || echo '否')"
echo
# Simulate SQL construction
echo "模拟SQL构造:"
TEST_SQL="UPDATE xg_student_msg SET student_status = '2' WHERE id = '$student_id';"
echo " $TEST_SQL"
echo
# Test SQL execution (dry run - just show what would be executed)
echo "SQL执行测试 (仅显示,不实际执行):"
echo " mysql -h'$DB_HOST' -P'$DB_PORT' -u'$DB_USER' -p'***' '$DB_NAME' -e \"$TEST_SQL\""
done
else
echo "没有找到数据行,检查是否有待处理的记录"
fi
echo
echo "=== 脚本兼容性检查 ==="
# Check bash features
echo "Bash特性检查:"
echo " 支持pipefail: $(set -o | grep pipefail)"
echo " 支持nounset: $(set -o | grep nounset)"
echo
echo "=== 环境变量检查 ==="
echo "PATH: $PATH"
echo "LD_LIBRARY_PATH: ${LD_LIBRARY_PATH:-未设置}"
echo
echo "=== 建议的修复方案 ==="
echo "如果上述解析失败,请尝试以下修改:"
echo "1. 在脚本开头添加: export LANG=C"
echo "2. 修改MySQL查询使用 -ss 参数而不是 -B"
echo "3. 检查数据表中是否有实际的待处理记录"
echo "4. 验证operator_id字段是否可能为NULL"
echo
echo "=== 调试完成 ==="
echo "请将上述输出结果发送给开发人员"