Shell脚本操作MariaDB建表插数报cut、SQL语法等错误求助
问题现象
运行Shell脚本实现MariaDB自动建表、插入CSV统计数据时抛出以下错误:
ERROR 1366 (22007) at line 1: Incorrect integer value: '' for column `a4_mgarr048_count`.`airline`.`total` at row 1 cut: option requires an argument -- 'f' ERROR 1366 (22007) at line 1: Incorrect integer value: '' for column `a4_mgarr048_count`.`airline`.`total` at row 1 cut: you must specify a list of bytes, characters, or fields at line 1: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '(name varchar(255), tot al int)' at line 1
原问题脚本如下:
readarray -d , -t header <<< "gender,state,municipality,season,continent,elective,f1,airline" for (( n=0; n < ${#header[@]} +1 ; n++)) do mysql -D a4_mgarr048_count -e "create table ${header[n]} (name varchar(255),total int);" done readarray -d , -t header <<< "gender:4,state:6,municipality:7,season:8,continent:9,elective:10,f1:11,airline:12" for (( n=0; n < ${#header[@]} +1; n++)) do readarray -d : -t fields <<< ${header[n]} while read line do mysql -D a4_mgarr048_count -e "insert into ${fields[0]} values ('$(echo $line | cut -d, -f2)','$(echo $line | cut -d, f1)')" done < <(cat /root/mgarr048.csv | cut -d, -f${fields[1]} | sort | uniq -c |sed -e 's/^\s*//g' -e 's/ /,/g') done
错误原因排查
- 数组循环越界:Bash数组下标从0开始,
${#header[@]}返回数组元素总个数,循环条件写n < ${#header[@]} +1会导致最后一次循环读取到下标等于数组长度的空元素,执行建表语句时表名为空,直接触发SQL语法错误。 - cut命令参数书写错误:插入语句中第二个cut命令写为
cut -d, f1,缺少参数前缀-,导致cut无法识别字段参数,直接抛出参数缺失错误,且该命令无输出,传给int类型total字段的是空字符串,触发1366类型不匹配错误。 - 不可见字符导致SQL语法异常:使用
readarray -d ,分割字符串时,here-string末尾自带的换行符会被存入最后一个数组元素中,导致表名、字段名夹带换行符,最终SQL语句出现异常断行(报错中total被拆分为带大段空白的断行内容就是该问题导致)。 - 冗余管道增加额外开销:使用
cat 文件 | cut的写法属于不必要的管道调用,会额外创建进程。
修复方案
修正后的可运行脚本如下:
#!/bin/bash # 建表逻辑 readarray -d , -t header <<< "gender,state,municipality,season,continent,elective,f1,airline" for (( n=0; n < ${#header[@]} ; n++)) do # 去除元素中夹带的换行、空白字符 table_name=$(echo "${header[n]}" | tr -d '\n\r ') mysql -D a4_mgarr048_count -e "create table if not exists ${table_name} (name varchar(255),total int);" done # 数据插入逻辑 readarray -d , -t header <<< "gender:4,state:6,municipality:7,season:8,continent:9,elective:10,f1:11,airline:12" for (( n=0; n < ${#header[@]}; n++)) do readarray -d : -t fields <<< ${header[n]} table_name=$(echo "${fields[0]}" | tr -d '\n\r ') col_num=$(echo "${fields[1]}" | tr -d '\n\r ') while read line do # 修正cut参数,按uniq -c输出顺序匹配字段:f1是计数(total)、f2是维度值(name) val_name=$(echo "$line" | cut -d, -f2) val_total=$(echo "$line" | cut -d, -f1) mysql -D a4_mgarr048_count -e "insert into ${table_name} (name, total) values ('${val_name}', ${val_total});" done < <(cut -d, -f${col_num} /root/mgarr048.csv | sort | uniq -c | sed -e 's/^\s*//g' -e 's/ /,/g') done
修复点说明:
- 调整循环边界为
n < ${#header[@]},避免数组越界读取空值;新增if not exists判断,避免重复建表报错。 - 补全cut命令缺失的
-前缀,修正参数错误。 - 对所有从数组读取的表名、列号做过滤,删除换行、回车、空格等不可见字符,避免SQL异常断行。
- 插入SQL显式指定字段顺序,确保字符串类型的name、整数类型的total和传入值一一对应,避免类型不匹配错误。
- 去掉冗余的cat管道,cut直接读取目标CSV文件,减少不必要的进程开销。
内容的提问来源于stack exchange,提问作者Michael Garrido
相关产品推荐
相关产品推荐

