如何使用awk按特定条件实现文本行列转置?
行列转置需求的纯Awk实现方案
输入文件内容
cat f "0/35","0eij8401c "0/35","59ij41015 "0/35","21ij3e01c "0/35","dbije401b "1/35","dbij8a015 "1/35","67ijb9011 "1/35","b5ije001b "1/35","bdij3701d "2/35","abij3b011 "2/35","7fij70018 "2/35","77ijf9010 "2/35","e5ij64015 "3/35","59ij41015 "3/35","f6ijae01e "3/35","c4ij5801c "3/35","dbij98012 "4/35","edij6801e "4/35","pdij6801e "4/35","kdij6801e "4/35","8cij57018
转置规则
- 取第1、5、9、13、17行的第二列作为输出第一列
- 取第2、6、10、14、18行的第二列作为输出第二列
- 以此类推,最终生成4行5列的转置结果
期望输出
输出1(报表格式)
"0eij8401c "dbij8a015 "abij3b011 "59ij41015 "edij6801e "59ij41015 "67ijb9011 "7fij70018 "f6ijae01e "pdij6801e "21ij3e01c "b5ije001b "77ijf9010 "c4ij5801c "kdij6801e "dbije401b "bdij3701d "e5ij64015 "dbij98012 "8cij57018
输出2(单列格式)
0eij8401c dbij8a015 abij3b011 59ij41015 edij6801e 59ij41015 67ijb9011 7fij70018 f6ijae01e pdij6801e 21ij3e01c b5ije001b 77ijf9010 c4ij5801c kdij6801e dbije401b bdij3701d e5ij64015 dbij98012 8cij57018
当前尝试的方法
方法1:Awk拆分+Paste合并
通过Awk将每行第二列按每4行拆分到不同文件:
cat f | awk -v batchNo=1 -v Num=4 '{print $1 > "batch_" batchNo ".txt";if(NR%Num==0) {batchNo++}}'
生成5个中间文件:
ls batch_* batch_1.txt batch_2.txt batch_3.txt batch_4.txt batch_5.txt
再用Paste合并得到报表格式输出:
paste batch_1.txt batch_2.txt batch_3.txt batch_4.txt batch_5.txt
该方法能得到期望输出1,但依赖中间文件,需要纯Awk实现方案。
方法2:尝试的纯Awk命令(未成功)
awk '{a[$1]++; b[$2]++;c[$3]++;d[$4]++;e[$5]++} END {for (k in a) print k > "out.txt"; for (j in b) print j > "out.txt";for (k in c) print j > "out.txt";for(l in d) print l> "out.txt"; for (m in e) print m> "out.txt";}' batch_*
未得到理想结果。
纯Awk解决方案
实现期望输出1(报表格式)
核心思路:用二维数组存储每行第二列,行索引为(NR-1)%4,列索引为int((NR-1)/4),最后按行输出数组内容:
awk -F, '{arr[(NR-1)%4][int((NR-1)/4)] = $2} END {for(i=0;i<4;i++){for(j=0;j<5;j++){printf "%s ", arr[i][j]} print ""}}' f
-F,:指定逗号为分隔符,提取第二列$2(NR-1)%4:计算当前行对应的输出行号(0-3)int((NR-1)/4):计算当前行对应的输出列号(0-4)- 遍历数组按行输出,每列用两个空格分隔
实现期望输出2(单列格式)
核心思路:按列遍历二维数组,依次输出元素,同时可选择去掉引号:
awk -F, '{arr[(NR-1)%4][int((NR-1)/4)] = $2} END {for(j=0;j<5;j++){for(i=0;i<4;i++){sub(/"/,"",arr[i][j]); print arr[i][j]}}}' f
sub(/"/,"",arr[i][j]):去掉字符串两端的引号(不需要可省略)- 先按列索引遍历,再按行索引遍历,实现目标单列顺序
内容的提问来源于stack exchange,提问作者VIPIN KUMAR
相关产品推荐
相关产品推荐

