使用Bash以CSV格式独立填充每行的列数(基于预期值)

问题描述 投票:1回答:2

我有一个CSV文件,其中行的理想格式是:

taxID#,学名,王国,k,门,p,class,c,order,o,family,f,genus,g

...其中王国,门等是标识符,文字(“王国”,......“门”),标识符后面的值(k,p等)是这些王国的实际值,门等

例:

240395,Rugosa emeljanovi,kingdom,Metazoa,phylum,Chordata,class,Amphibia,order,Anura,family,Ranidae,genus,Rugosa

但是,并非所有行都具有所有级别的分类,即任何一行都可能缺少标识符/值对的列,例如“class,c”,并且任何2列PAIR都可能会丢失而与其他对缺失无关或不。此外,如果缺少字段,它们的标识符字段将永远丢失,所以我永远不会将“王国,门”放在一起,而它们之间没有“k”的值。因此,我的大部分文件都缺少随机字段:

...
135487,Nocardia cyriacigeorgica,class,Actinobacteria,order,Corynebacteriales,genus,Nocardia
10090,Mus musculus,kingdom,Metazoa,phylum,Chordata,class,Mammalia,order,Rodentia,family,Muridae,genus,Mus
152507,uncultured actinobacterium,phylum,Actinobacteria,class,Actinobacteria
171953,uncultured Acidobacteria bacterium,phylum,Acidobacteria
77133,uncultured bacterium
...

问题:如何编写一个bash shell脚本,可以“填充”文件中的每一行,以便插入可能缺少理想格式的每个字段对,并且其后面的值列只是空白。期望的输出:

...
135487,Nocardia cyriacigeorgica,kingdom,,phylum,,class,Actinobacteria,order,Corynebacteriales,family,,genus,Nocardia
10090,Mus musculus,kingdom,Metazoa,phylum,Chordata,class,Mammalia,order,Rodentia,family,Muridae,genus,Mus
152507,uncultured actinobacterium,kingdom,,phylum,Actinobacteria,class,Actinobacteria,order,,family,,genus,
171953,uncultured Acidobacteria bacterium,phylum,Acidobacteria,clas,,order,,family,,genus,
77133,uncultured bacterium,kingdom,,phylum,,class,,order,,family,,genus,
...

笔记:

  • 请注意,如果缺少某个属,则填充的输出应以逗号结尾,以表示属的值不存在。
  • taxID#和科学名称(前两个字段)将始终存在。
  • 如果您的解决方案非常强大,我不关心时间/资源效率。

我尝试过的:

  • 我写了一个简单的if / then脚本,它按顺序检查预期的字段是否消失了。伪代码: 如果“$ f3”不是“王国”,请填写 但问题是,如果王国真的失踪了,它会在输出中填补,但其余的场变量将被哄骗,我不能只是通过说 如果“$ f5”不是“门”,请填写 因为如果王国失踪,门可能现在在第3场($ f3),而不是$ f5,也就是说,如果它也没有丢失。 (我这样做是通过将一个字符串变量连接到基于每个字段缺失的预期输出,并简单地连接原始值,如果该字段没有丢失,然后回显完成的,假设填充的行输出)。

我希望能够像这样执行我的脚本

bash pad.sh prePadding.csv postPadding.csv

但如果需要,我会接受使用Mac Excel 2011的答案。

谢谢!!

bash shell csv pad
2个回答
1
投票

这将是bash使用关联数组的答案:

#!/bin/bash

declare -A THIS
while IFS=, read -a LINE; do
  # we always get the #ID and name
  if (( ${#LINE[@]} < 2 || ${#LINE[@]} % 2 )); then
    echo Invalid CSV line: "${LINE[@]}" >&2
    continue
  fi
  echo -n "${LINE[0]},${LINE[1]},"
  THIS=()
  for (( INDEX=2; INDEX < ${#LINE[@]}; INDEX+=2 )); do
    THIS[${LINE[INDEX]}]=${LINE[INDEX+1]}
  done
  for KEY in kingdom phylum class order family; do
    echo -n $KEY,${THIS[$KEY]},
  done
  echo genus,${THIS[genus]}
done <$1 >$2

它还验证CSV行,使它们包含至少2列(ID和名称),并且它们具有偶数列。

可以扩展脚本以进行更多的错误检查(即,如果两个参数都被传递,如果输入存在,等等),但它应该按照您发布它的方式按预期工作。


2
投票

虽然它应该可以在bash中使用,但我会使用Perl。我试着让代码尽可能简单易懂。

#!/usr/bin/perl

while (<>){
    chomp;
    my @fields=split ',';
    my $kingdom='';
    my $phylum='';
    my $class='';
    my $order='';
    my $family='';
    my $genus='';
    for (my $i=2;$i<$#fields;$i+=2){
        if ($fields[$i] eq 'kingdom'){$kingdom=$fields[$i+1];}
        if ($fields[$i] eq 'phylum'){$phylum=$fields[$i+1];}
        if ($fields[$i] eq 'class'){$class=$fields[$i+1];}
        if ($fields[$i] eq 'order'){$order=$fields[$i+1];}
        if ($fields[$i] eq 'family'){$family=$fields[$i+1];}
        if ($fields[$i] eq 'genus'){$genus=$fields[$i+1];}
    }
    print "$fields[0],$fields[1],kingdom,$kingdom,phylum,$phylum,class,$class,order,$order,family,$family,genus,$genus\n";
}

这给了我:

perl pad.pl  input
135487,Nocardia cyriacigeorgica,kingdom,,phylum,,class,Actinobacteria,order,Corynebacteriales,family,,genus,Nocardia
10090,Mus musculus,kingdom,Metazoa,phylum,Chordata,class,Mammalia,order,Rodentia,family,Muridae,genus,Mus
152507,uncultured actinobacterium,kingdom,,phylum,Actinobacteria,class,Actinobacteria,order,,family,,genus,
171953,uncultured Acidobacteria bacterium,kingdom,,phylum,Acidobacteria,class,,order,,family,,genus,

(或者为了更好的阅读:)

perl pad.pl  input  | tableize -t | sed 's/^/    /'
+------+----------------------------------+-------+-------+------+--------------+-----+--------------+-----+-----------------+------+-------+-----+--------+
|135487|Nocardia cyriacigeorgica          |kingdom|       |phylum|              |class|Actinobacteria|order|Corynebacteriales|family|       |genus|Nocardia|
+------+----------------------------------+-------+-------+------+--------------+-----+--------------+-----+-----------------+------+-------+-----+--------+
|10090 |Mus musculus                      |kingdom|Metazoa|phylum|Chordata      |class|Mammalia      |order|Rodentia         |family|Muridae|genus|Mus     |
+------+----------------------------------+-------+-------+------+--------------+-----+--------------+-----+-----------------+------+-------+-----+--------+
|152507|uncultured actinobacterium        |kingdom|       |phylum|Actinobacteria|class|Actinobacteria|order|                 |family|       |genus|        |
+------+----------------------------------+-------+-------+------+--------------+-----+--------------+-----+-----------------+------+-------+-----+--------+
|171953|uncultured Acidobacteria bacterium|kingdom|       |phylum|Acidobacteria |class|              |order|                 |family|       |genus|        |
+------+----------------------------------+-------+-------+------+--------------+-----+--------------+-----+-----------------+------+-------+-----+--------+
© www.soinside.com 2019 - 2024. All rights reserved.