sed 或 awk 命令在特定位置插入制表符(分隔符)

sed 或 awk 命令在特定位置插入制表符(分隔符)

我正在尝试解析具有可变数量分隔符的表,以将其转换为相等列的表:

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 版本中)。

相关内容