我正在尝试解析具有可变数量分隔符的表,以将其转换为相等列的表:
cluster=96\troot\tcellular organisms\tno_rank no_rank$
cluster=42\troot\tcellular organisms\tBacteria\tno_rank\tno_rank\tsuperkingdom$
cluster=362\troot\tcellular organisms\tBacteria\tProteobacteria\tno rank\tno rank\tsuperkingdom\tphylum$
cluster=12330\troot\tcellular organisms\tBacteria\tTerrabacteria\tFirmicutes\tClostridia\tClostridiales\tClostridiaceae\tClostridium\tno rank\tno rank\tsuperkingdom\tno rank\tphylum\tclass\torder\tfamily\tgenus$
预期输出是:
cluster=96\troot\tcellular organisms\t\t\t\t\t\t\t\tno_rank\tno_rank\t\t\t\t\t\t\t$
cluster=42\troot\tcellular organisms\tBacteria\t\t\t\t\t\t\tno_rank\tno_rank\tsuperkingdom\t\t\t\t\t\t$
cluster=362\troot\tcellular organisms\tBacteria\tProteobacteria\t\t\t\t\t\tno rank\tno rank\tsuperkingdom\tphylum\t\t\t\t\t$
cluster=12330\troot\tcellular organisms\tBacteria\tTerrabacteria\tFirmicutes\tClostridia\tClostridiales\tClostridiaceae\tClostridium\tno rank\tno rank\tsuperkingdom\tno rank\tphylum\tclass\torder\tfamily\tgenus$
“\t”是制表符分隔符,“$”是行尾
答案1
使用 Awk 进行两次传递:
awk -F'\t' -v OFS='\t' 'FNR==NR {if (NF>a) {a=NF}; next} NF<a{$a=""} 1' file file
这将在以下位置添加额外的选项卡结尾缺少字段的行。
根据您的确切示例数据,我认为您可能正在处理一个无法以编程方式解决的问题。如果您需要在中间位置添加额外的选项卡以确保no_rank
值最终出现在右列中,则您将需要一些更奇特的逻辑。
答案2
使用磨坊主: 我回答过类似的问题此处为 CSV但在这种情况下,标题行中已经提供了最大长度,因此无需在其他地方搜索它。
在这种情况下,最大长度可能在其他地方,我能做的最好的事情是:
cat in.dat | mlr --nidx --fs tab --nidx put -q '
@maxnf = max(@maxnf, NF);
@records[NR] = $*; # Retain
@counts[NR] = NF;
end {
for (i in @records) {
@record = @records[i];
for (j = @counts[i] + 1; j <= @maxnf; j += 1) { # add extra fields
@record["x".j] = "";
}
emit @record; # insert into the output record stream
}
}
'
想法是保留record-list和max NF;然后在结束块中进行处理。请注意,这使用了 head 中的功能(不在最新的 4.5.0 版本中)。