Linux/Posix环境下Bash解析含引号内逗号的多行CSV至变量
用POSIX默认工具解析含引号内逗号的CSV并逐行存变量
问题分析
直接依赖IFS=,分割CSV会误将引号内的逗号识别为字段分隔符,破坏字段结构;使用awk虽能完成解析,但需要解决字段向shell变量传递、指定行号处理的问题。
解决方案:shell内置工具+awk配合实现
1. 核心思路
用awk完成CSV的合规解析(识别引号内逗号为字段内容而非分隔符),通过**空字符(\0)**作为字段输出分隔符(CSV标准字段不会包含空字符,避免冲突),再由shell逐行读取并分割字段存入变量,同时awk可指定处理特定行号。
2. 完整代码示例
假设示例CSV内容如下:
id,name,company,email
1,John Doe,"AC XA, S.A.",john@example.com
2,Jane Smith,"Tech Corp, Inc.",jane@example.org
处理脚本:
#!/bin/sh # 处理第2行(跳过表头),如需处理所有行则删除NR==2条件;跳过表头用NR>1 awk -F ',' ' NR==2 { n = 0 in_quote = 0 current = "" for (i=1; i<=NF; i++) { current = current $i # 统计当前片段的引号数量 gsub(/"/, "", temp = current) quote_count = length(current) - length(temp) if (quote_count % 2 != 0) { in_quote = !in_quote if (!in_quote) { # 引号闭合,清理字段首尾引号后存入数组 sub(/^"/, "", current) sub(/"$/, "", current) fields[++n] = current current = "" } else { # 引号未闭合,拼接逗号继续读取后续片段 current = current "," } } else { if (!in_quote) { # 无引号或引号已闭合,清理后存入数组 sub(/^"/, "", current) sub(/"$/, "", current) fields[++n] = current current = "" } else { # 引号内的逗号,直接拼接 current = current "," } } } # 用空字符分隔字段输出,确保字段含空格/特殊字符时不被拆分 for (i=1; i<=n; i++) { printf "%s%c", fields[i], (i == n ? "\n" : "\0") } }' sample.csv | while IFS=$'\0' read -r id name company email; do # 后续处理逻辑示例 echo "ID: $id" echo "Name: $name" echo "Company: $company" echo "Email: $email" echo "---" done
3. 纯shell实现(无awk依赖)
若需完全依赖shell内置命令,可通过逐字符跟踪引号状态实现解析:
#!/bin/sh while IFS= read -r line; do # 跳过表头行 if [ "$line" = "id,name,company,email" ]; then continue fi in_quote=0 fields=() current="" # 逐字符遍历行内容 for ((i=0; i<${#line}; i++)); do char="${line:i:1}" if [ "$char" = '"' ]; then in_quote=$((1 - in_quote)) continue # 跳过引号本身,不存入字段 fi if [ "$char" = ',' ] && [ $in_quote -eq 0 ]; then # 非引号内的逗号,分割字段 fields+=("$current") current="" else current="$current$char" fi done # 加入最后一个字段 fields+=("$current") # 字段存入变量 id="${fields[0]}" name="${fields[1]}" company="${fields[2]}" email="${fields[3]}" # 后续处理逻辑示例 echo "ID: $id" echo "Name: $name" echo "Company: $company" echo "Email: $email" echo "---" done < sample.csv
这种方法无需外部工具,但逻辑繁琐,仅适合字段无换行的简单CSV场景。
注意事项
- 若CSV包含多行字段(字段内有换行),纯shell的
read会截断内容,此时优先选择awk方案,awk可读取多行直到引号闭合。 - 确保CSV格式合规:字段内引号成对出现,无未闭合的引号。
内容的提问来源于stack exchange,提问作者user3665852
相关产品推荐
相关产品推荐

