如何使用Bash处理CSV文件 合并交替行生成分号分隔的成对记录
跨行配对转分号分隔CSV的实现方案
你的需求本质是按「用户名行+日期行」的固定两两配对规则做行合并,以下是几种可直接运行的实现,覆盖你之前尝试的read命令方向:
方案1:Bash 原生read实现(匹配你最初的尝试方向)
逐行读取文件内容,遇到uid:开头的行暂存用户名,读到紧随其后的日期行就拼接输出,逻辑完全贴合配对规则,不会出现错位:
#!/bin/bash # 初始化输出文件 > newcsv.csv username="" while IFS= read -r raw_line; do # 去除每行首尾的空白字符,兼容原文件行尾多余空格 line=$(echo "$raw_line" | xargs) if [[ $line == uid:* ]]; then # 截掉uid:前缀,提取用户名 username=${line#uid:} elif [[ -n $username && $line =~ ^[0-9]{8}$ ]]; then # 已暂存用户名、且当前行为8位日期时,拼接写入结果 echo "$username;$line" >> newcsv.csv # 清空暂存的用户名,避免后续行错位 username="" fi done < csv.csv
给脚本加执行权限后直接运行即可生成目标文件。
方案2:Awk 一行命令(高效简洁,适合快速处理)
Awk天生适合流文本的跨行处理,不需要写复杂循环,一行命令就能完成转换:
awk ' { gsub(/^[[:space:]]+|[[:space:]]+$/,"",$0) } /^uid:/ { user = substr($0, 5); next } { print user ";" $0 } ' csv.csv > newcsv.csv
逻辑拆解:
- 第一步先统一去掉每行首尾的空白,避免多余空格干扰匹配
- 匹配到
uid:开头的行时,截取uid:之后的内容存为用户名变量,跳过当前行后续处理 - 其余行(即日期行)直接用暂存的用户名和当前日期拼接输出
方案3:Sed 流编辑实现(无额外变量依赖)
通过Sed的N命令直接把相邻两行读入同一模式空间做正则替换,不需要暂存变量:
sed -E ' N s/^[[:space:]]*uid:([^[:space:]]+)[[:space:]]*\n[[:space:]]*([0-9]+)[[:space:]]*$/\1;\2/ ' csv.csv > newcsv.csv
逻辑拆解:
N:读取下一行追加到当前行后,两行用换行符分隔- 正则匹配
uid:用户名 + 换行 + 日期的结构,直接替换为用户名;日期的目标格式,同时自动过滤所有多余空白
避坑提示:如果你的csv.csv是Windows下生成的,先执行
dos2unix csv.csv转换换行符格式,避免read/awk/sed读取时出现行尾\r导致的格式错误。
内容的提问来源于stack exchange,提问作者vinc.slg
相关产品推荐
相关产品推荐

