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

时间:2018-03-03 04:57:42

标签: bash shell csv pad

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

taxID#科学名称,王国, k ,门, p ,班级, c ,订单, o ,家庭, f ,genus, g

......其中王国,门等是标识符,文字("王国",..."门"),以及标识符后面的值(k, p等,是那些王国,门等的实际值。

示例:

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

但是,并非所有行都具有所有级别的分类,即任何一行都可能缺少标识符/值对的列,例如," class,c,&#34 ;并且任何2列PAIR都可以独立于其他对缺失而丢失。此外,如果字段丢失,它们的标识符字段将永远丢失,所以我永远不会得到王国,门和#34;没有" 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
...

问题:如何编写一个可以" pad"的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的答案。

谢谢!

1 个答案:

答案 0 :(得分: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和名称),并且它们具有偶数列。

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