使用awk实现行列转换时遇到最后一行处理异常问题
看起来你遇到的问题出在awk命令的循环终止条件上——你在END块里用了i<=NR,但NR是输入的总行数,而我们需要遍历的是原文件的列数(也就是数组A的索引范围)。
问题分析
你的原命令里,END部分的循环是for(i=1; i<=NR; i++) print A[i],这里的NR是你输入文件的行数(在你的例子里是3),但你的输入每行有5个字段(列),所以数组A里实际存储了A[1]到A[5]的内容。当循环只到NR=3时,后面的A[4]和A[5]根本没被打印,这就是你觉得“最后一行无法正确转置”的原因(推测你之前贴的错误输出是笔误,实际应该是缺少后面的行)。
另外,原命令里的(NR>1?OFS:x)中x是未定义变量,虽然awk会默认把它当作空字符串,但换成(A[i] ? OFS : "")会更清晰,意思是:如果当前列已经有内容(不是第一行的该列),就先加分隔符,再追加当前字段。
修正后的解决方案
单行awk命令(适用于每行字段数一致的情况)
awk '{for(i=1; i<=NF; i++) A[i] = A[i] (A[i] ? OFS : "") $i} END{for(i=1; i<=length(A); i++) print A[i]}' OFS="\t" input.txt > output.txt
更稳健的版本(适配每行字段数不一致的情况)
如果你的文件存在每行字段数不同的情况,建议记录最大列数来避免遗漏:
awk '{ for(i=1; i<=NF; i++) { A[i] = A[i] (A[i] ? OFS : "") $i } if(NF > maxNF) maxNF = NF } END { for(i=1; i<=maxNF; i++) { print A[i] } }' OFS="\t" input.txt > output.txt
批量处理多文件夹下的文件
针对你提到的“多个文件夹每个都包含一个文本文件”的场景,可以用bash循环批量处理:
# 遍历所有子文件夹下的txt文件 for file in */*.txt; do # 生成转置后的文件名(例如将input.txt转为input_transposed.txt) output_file="${file%.txt}_transposed.txt" awk '{for(i=1; i<=NF; i++) A[i] = A[i] (A[i] ? OFS : "") $i} END{for(i=1; i<=length(A); i++) print A[i]}' OFS="\t" "$file" > "$output_file" done
用你提供的input.txt测试,修正后的命令会输出你期望的结果:
ID1 ID2 ID3 11208 6691 5768 13391 8489 6004 16070 8723 7754 19383 7493 7614
内容的提问来源于stack exchange,提问作者Antonis G
相关产品推荐
相关产品推荐

