按多列值拆分TSV文件并保留表头的技术实现疑问
解决TSV文件按多列拆分时表头缺失的问题
我来帮你搞定这个拆分TSV文件时表头只在部分文件出现的问题~
原命令的问题分析
你原来的awk命令里,判断是否输出表头的条件!a[$5]++ && !a[$9]++ && !a[$10]++逻辑不对:它要求第5列的值是第一次出现、第9列的值是第一次出现、第10列的值也是第一次出现这三个条件同时满足时,才会输出表头。但实际上我们需要的是当第5、9、10列的组合是第一次出现时就输出表头,和单个列的值是否出现过无关。比如组合1-2-3,哪怕1、2、3各自都在其他组合里出现过,但这个组合是第一次出现,就应该给对应的文件加上表头。
修正后的awk命令
下面是调整后的命令,能保证每个拆分出来的文件都正确保留表头:
awk -F'\t' ' NR == 1 { # 保存表头内容 header = $0 next } { # 用第5、9、10列的组合生成唯一键,用来标记这个组合是否已经处理过 key = $5 "_" $9 "_" $10 # 生成目标文件名 filename = "file_first-" $5 "_second-" $9 "_third-" $10 ".tsv" # 如果这个组合是第一次出现,先写入表头 if (!seen[key]++) { print header > filename } # 追加当前行到目标文件 print >> filename } ' file.tsv
命令解释
NR == 1:处理第一行时,把表头内容保存到变量header里,然后用next跳过后续逻辑,直接处理下一行。key = $5 "_" $9 "_" $10:把三个列的值拼接成一个唯一的字符串,作为判断组合是否重复的标识。!seen[key]++:数组seen用来记录每个组合是否已经处理过,第一次遇到某个组合时,这个条件为真,就会先写入表头。print >> filename:用>>而不是>来追加内容,避免覆盖已经写入的表头和之前的行。
额外提示
如果你的TSV文件特别大,或者拆分出来的文件数量极多,部分旧版本的awk可能会因为打开过多文件描述符报错。这种情况下,可以在每次处理完一个组合后关闭文件,不过对于大多数日常场景,上面的命令已经足够好用了。
内容的提问来源于stack exchange,提问作者Dagbi Akerson
相关产品推荐
相关产品推荐

