Linux下用Bash Shell脚本连接到MySQL数据库,用SELECT @@secure_file_priv或者SHOW QUERY VARIABLE LIKE 'secure_file_priv’取得secure_file_priv变量的值,值为Linux的目录,如果获取的值为空,则输出提示信息让用户配置my.cnf文件中的secure_file_priv变量的值,否则打印输出这个值,说明输出文件到这个目录,并且实现一个基于多个带标签SQL模板作为配置文件和多组参数的Bash Shell脚本、SELECT INTO OUTFILE语句和mysql命令行程序,实现根据不同的输入参数,自动批量地将MySQL数据库的数据导出为字段用引号包裹以及带逗号分隔的CSV文件和到指定目录上,标签和多个参数(以“_”分割)为组成导出数据文件名,文件已经存在则覆盖原始文件。Bash Shell脚本需要异常处理,输出带时间戳和每个运行批次和每个导出文件作业运行状态的日志文件,每天单独一个带日期的和.log扩展名日志文件,放在logs子目录中,参数全部设置在json配置文件中。
#!/bin/bash
set -eo pipefail
# 读取配置文件
CONFIG_FILE="config.json"
# 解析JSON配置
parse_config() {
jq -r '.database | "\(.host) \(.user) \(.password) \(.database)"' "$CONFIG_FILE" | read host user password database
template_dir=$(jq -r '.export.template_dir' "$CONFIG_FILE")
output_dir=$(jq -r '.export.output_dir' "$CONFIG_FILE")
log_dir=$(jq -r '.logging.log_dir' "$CONFIG_FILE")
mapfile -t tasks < <(jq -c '.export.tasks[]' "$CONFIG_FILE")
}
# 初始化日志系统
setup_logging() {
mkdir -p "$log_dir"
log_file="${log_dir}/$(date +%Y%m%d).log"
touch "$log_file"
}
# 日志记录函数
log() {
local status=$1
local message=$2
echo "[$(date '+%Y-%m-%d %T')] [${current_task}] [${status}] ${message}" >> "$log_file"
}
# 检查secure_file_priv配置
check_secure_file_priv() {
local secure_file_priv=$(mysql -h"$host" -u"$user" -p"$password" -sN -e "SELECT @@secure_file_priv;")
if [[ -z "$secure_file_priv" || "$secure_file_priv" == "NULL" ]]; then
log "ERROR" "secure_file_priv未配置,请修改my.cnf文件"
exit 1
else
log "INFO" "secure_file_priv配置为:${secure_file_priv}"
if [[ ! "$output_dir" =~ ^$secure_file_priv ]]; then
log "ERROR" "输出目录必须在secure_file_priv路径下"
exit 1
fi
fi
}
# 执行数据导出
export_data() {
local label=$1
local params=(${2//_/ })
local template_file="${template_dir}/${label}.sql"
local output_file="${output_dir}/${label}_${2}.csv"
# 处理SQL模板
if [[ ! -f "$template_file" ]]; then
log "ERROR" "模板文件不存在:${template_file}"
return 1
fi
# 替换模板参数
sql_query=$(<"$template_file")
for i in "${!params[@]}"; do
param_name="param$((i+1))"
param_value="${params[$i]//\'/\\\'}"
sql_query=${sql_query//\{\{${param_name}\}\}/${param_value}}
done
# 构建完整SQL语句
sql_query+=" INTO OUTFILE '${output_file}'
FIELDS TERMINATED BY ','
ENCLOSED BY '\"'
ESCAPED BY '\"'
LINES TERMINATED BY '\\n'"
# 执行导出
log "INFO" "开始导出:${output_file}"
if mysql -h"$host" -u"$user" -p"$password" -D"$database" -e "$sql_query" 2>> "$log_file"; then
log "SUCCESS" "导出成功"
else
log "ERROR" "导出失败"
return 1
fi
}
# 主执行流程
main() {
parse_config
setup_logging
check_secure_file_priv
mkdir -p "$output_dir"
for task in "${tasks[@]}"; do
label=$(jq -r '.label' <<< "$task")
mapfile -t params_list < <(jq -cr '.params[] | join("_")' <<< "$task")
for params in "${params_list[@]}"; do
current_task="${label}_${params}"
log "INFO" "开始处理任务"
if export_data "$label" "$params"; then
log "INFO" "任务处理完成"
else
log "ERROR" "任务处理失败"
fi
done
done
}
main
配套的config.json示例:
{
"database": {
"host": "localhost",
"user": "root",
"password": "your_password",
"database": "test_db"
},
"export": {
"template_dir": "./sql_templates",
"output_dir": "/var/lib/mysql-files/exports",
"tasks": [
{
"label": "users",
"params": [
["active", "2023"],
["inactive", "2022"]
]
},
{
"label": "orders",
"params": [
["pending"],
["completed"]
]
}
]
},
"logging": {
"log_dir": "./logs",
"log_level": "INFO"
}
}
SQL模板示例(sql_templates/users.sql):
SELECT *
FROM users
WHERE status = '{{param1}}'
AND YEAR(created_at) = '{{param2}}'
脚本特点:
- 安全验证:自动检查MySQL的secure_file_priv配置
- 模板引擎:支持带{{param}}占位符的SQL模板
- 批量处理:支持多任务多参数批量执行
- 日志系统:
- 每天生成独立日志文件
- 包含时间戳和任务状态
- 自动创建日志目录
- 错误处理:
- 自动捕获并记录错误
- 模板文件存在性检查
- MySQL执行错误处理
- 文件管理:
- 自动创建输出目录
- 文件名自动生成(标签_参数1_参数2.csv)
- 自动覆盖已有文件
使用说明:
- 将配置文件保存为config.json
- 创建sql_templates目录并放置SQL模板文件
- 确保MySQL用户有FILE权限和目标目录写入权限
- 通过chmod +x script.sh添加执行权限
- 使用./script.sh执行脚本
注意事项:
- MySQL的secure_file_priv目录需要提前配置
- 确保JSON配置文件的语法正确
- SQL模板中的参数占位符使用双大括号格式{{param}}
- 输出目录必须位于secure_file_priv指定的路径下
- 建议在生产环境中使用配置文件权限限制(如chmod 600 config.json)