Bash入门者求助:如何用Awk合并CSV中第二列相同的行
解决CSV按第二列合并行并保留第三列的Awk方案
嘿,我来帮你搞定这个问题!你的核心思路是对的,但问题出在没有单独存储第三列(Value)的信息——原来的代码只跟踪了合并后的Name,所以输出时要么拿不到Value,要么错误地重复了Name内容。
问题分析
你原来的代码里,数组a[$2]只存了合并后的Name字符串,完全没保存对应的Value。当你在END块里想输出第三列时,错误地用了a[i](也就是Name)来填充,自然会重复显示第一列内容。
而且题目里明确说了“当两行的第二列相同时,第三列也必然相同”,这意味着我们只需要在第一次遇到某个Num时保存对应的Value就行,后续不用更新。
修改后的Awk代码
这里用两个数组分别跟踪合并后的Name和对应的Value:
BEGIN{FS=","; OFS=","} NR==1{print; next} { # 处理Name列的合并:如果已存在则追加,否则初始化 names[$2] = ($2 in names) ? names[$2] " " $1 : $1 # 仅在第一次遇到该Num时保存对应的Value if (!($2 in values)) { values[$2] = $3 } } END{ # 遍历所有Num,输出合并后的结果 for (num in names) { print names[num], num, values[num] } }
代码解释
- BEGIN块:设置输入分隔符
FS和输出分隔符OFS为逗号,这样输出时自动用逗号分隔列,不用手动拼接,。 - 表头处理:第一行直接打印表头,然后
next跳过后续逻辑。 - 主体逻辑:
- 对于每一行,检查当前Num(
$2)是否已经在names数组中:如果是,就把当前Name($1)用空格追加到已有内容后;如果不是,就初始化names[$2]为当前Name。 - 同时,如果这个Num还没在
values数组里,就把对应的Value($3)存进去——因为题目保证相同Num的Value一致,所以只需要存一次。
- 对于每一行,检查当前Num(
- END块:遍历所有存储的Num,按顺序输出合并后的Name、Num、Value。
简化版代码(用三元表达式)
如果喜欢更简洁的写法,可以把主体逻辑压缩成一行:
BEGIN{FS=","; OFS=","} NR==1{print; next} { names[$2] = ($2 in names) ? names[$2] " " $1 : $1 !($2 in values) && (values[$2] = $3) } END{for (num in names) print names[num], num, values[num]}
测试结果
用你的示例输入运行这段代码,会得到完全符合预期的输出:
Name,Num,Value ex1 ex4,10.20.30.40,val1 ex2 ex5,20.30.40.30,val2 ex3,10.45.60.20,val3
内容的提问来源于stack exchange,提问作者Pablo
相关产品推荐
相关产品推荐

