1

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

taxID# ,学名, 王国, k , phylum, 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,
...

笔记:

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

我试过的:

  • 我编写了一个简单的 if/then 脚本,它会按顺序检查预期字段是否消失。伪代码:

    如果“$f3”不是“王国”,则填充

    但问题是如果王国真的失踪了,它会在输出中被填充,但剩余的字段变量会被弄乱,我不能只是说

    如果“$f5”不是“门”,则填充

    因为如果没有王国,门现在可能在字段 3 ($f3),而不是 $f5,也就是说,如果它也没有丢失的话。(我通过根据每个字段的缺失将预期输出连接到一个字符串变量上来做到这一点,并且如果该字段没有丢失,则简单地连接原始值,然后将完成的、应该填充的行回显到输出)。

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

bash pad.sh prePadding.csv postPadding.csv

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

谢谢!!

4

2 回答 2

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|        |
+------+----------------------------------+-------+-------+------+--------------+-----+--------------+-----+-----------------+------+-------+-----+--------+
于 2018-03-03T10:01:55.413 回答
1

这将是使用关联数组的 ba​​sh 中的答案:

#!/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 和名称)并且它们具有偶数列。

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

于 2018-03-03T12:16:09.083 回答