提取多文件匹配表头列并补全缺失值的AWK脚本问题
修正AWK脚本实现跨CSV文件提取指定列并填充缺失值
问题描述
现有两个CSV文件,需提取val 2和val 5对应的列,分别写入独立文件;其中file1.csv有5行数据,file2.csv有7行数据,缺失的数值用?填充。
源文件内容
# file1.csv cat << EOF > file1.csv val 1, val 2, val 5, val 6 34,12,23,54 22,32,22,43 12,32,11,31 32,32,44,22 32,34,23,45 EOF # file2.csv cat << EOF > file2.csv val 5, val 2, val 3, val 4, val 7 4,82,13,4,33 2,22,42,3,23 1,42,51,1,67 33,42,84,2,43 42,44,93,5,56 23,42,32,32,34 32,43,22,11,2 EOF
原AWK脚本
awk 'BEGIN { FS=", "; OFS=" " } NR==FNR { if (FNR > 1) { val2[FNR-1] = $2 val5[FNR-1] = $3 } next } { if (FNR > 1) { val2[FNR-1] = val2[FNR-1] " " $2 val5[FNR-1] = val5[FNR-1] " " $5 } } END { print "val 2" for (i=1; i<=NR; i++) { if (i <= length(val2)) { print val2[i] } else { print "?" } } print "" print "val 5" for (i=1; i<=NR; i++) { if (i <= length(val5)) { print val5[i] } else { print "?" } } }' file1.csv file2.csv
期望输出
# output_val_2.txt cat << EOF > output_val_2.txt 12 82 32 22 32 42 32 42 34 44 ? 42 ? 43 EOF # output_val_5.txt cat << EOF > output_val_5.txt 23 4 22 2 11 1 44 33 23 42 ? 23 ? 32 EOF
修正后的AWK脚本
awk 'BEGIN { FS=", "; OFS=" " } # 处理第一个文件file1.csv NR==FNR { if (FNR == 1) { # 动态识别val2和val5的列索引 for (i=1; i<=NF; i++) { if ($i == "val 2") col2_file1 = i if ($i == "val 5") col5_file1 = i } next } row = FNR - 1 val2[row] = $col2_file1 val5[row] = $col5_file1 max_rows = row next } # 处理第二个文件file2.csv { if (FNR == 1) { # 动态识别val2和val5的列索引 for (i=1; i<=NF; i++) { if ($i == "val 2") col2_file2 = i if ($i == "val 5") col5_file2 = i } # 更新最大行数为两个文件的较大值 if ((FNR - 1) > max_rows) max_rows = FNR - 1 next } row = FNR - 1 # 合并数据,缺失位置用?填充 val2[row] = (row in val2 ? val2[row] : "?") OFS $col2_file2 val5[row] = (row in val5 ? val5[row] : "?") OFS $col5_file2 # 更新最大行数 if (row > max_rows) max_rows = row } END { # 写入val2结果文件 print "val 2" > "output_val_2.txt" for (i=1; i<=max_rows; i++) { split(val2[i], parts) line = (parts[1] != "" ? parts[1] : "?") OFS (parts[2] != "" ? parts[2] : "?") # 对齐格式,?后补两个空格 if (line ~ /^\? /) line = "? " parts[2] print line > "output_val_2.txt" } close("output_val_2.txt") # 写入val5结果文件 print "val 5" > "output_val_5.txt" for (i=1; i<=max_rows; i++) { split(val5[i], parts) line = (parts[1] != "" ? parts[1] : "?") OFS (parts[2] != "" ? parts[2] : "?") if (line ~ /^\? /) line = "? " parts[2] print line > "output_val_5.txt" } close("output_val_5.txt") }' file1.csv file2.csv
关键修正说明
- 动态列索引:不再硬编码列位置,通过表头自动识别
val 2和val 5在两个文件中的列号,适配列顺序变化。 - 正确计算最大行数:取两个文件数据行的最大值(7行)作为循环上限,替代原脚本错误使用的总记录数
NR。 - 双向缺失值填充:同时处理file1缺失的行(补
?在第一个位置)和file2缺失的情况,确保每行都有两个值。 - 格式对齐:对包含
?的行做格式调整,保证和期望输出的空格对齐一致。 - 直接写入文件:将结果直接写入指定的输出文件,无需额外重定向操作。
内容的提问来源于stack exchange,提问作者Kay
相关产品推荐
相关产品推荐

