使用Linux命令进行复杂的CSV解析

使用Linux命令进行复杂的CSV解析,csv,awk,sed,command-line,Csv,Awk,Sed,Command Line,我有一个CSV日志文件,记录属性HA;血红蛋白;HC;高清;他。以下文件记录了6个条目(由上面的标题分隔) 我想提取每个条目的第三个属性(HC) HA;HB;HC;HD;HE a1;b1;14;d;e HA;HB;HC;HD;HE a2;b2;28;d;e HA;HB;HC;HD;HE a31;b31;44;d;e a32;b32;07;d;e HA;HB;HC;HD;HE a4;b4;0;d;e HA;HB;HC;HD;HE a51;b51;32;d;e a52;b52;0;d;e a53;b

我有一个CSV日志文件,记录属性
HA;血红蛋白;HC;高清;他
。以下文件记录了6个条目(由上面的标题分隔)

我想提取每个条目的第三个属性(
HC

HA;HB;HC;HD;HE
a1;b1;14;d;e
HA;HB;HC;HD;HE
a2;b2;28;d;e
HA;HB;HC;HD;HE
a31;b31;44;d;e
a32;b32;07;d;e
HA;HB;HC;HD;HE
a4;b4;0;d;e
HA;HB;HC;HD;HE
a51;b51;32;d;e
a52;b52;0;d;e
a53;b53;5;d;e
HA;HB;HC;HD;HE
a6;b6;10;d;e
每当每个条目记录了
n
HC
时,我想提取添加的
n
条目

上述文件的预期输出:

14
28
51
0
37
10
14
28
51
0
37
10

我知道我可以为此编写一个程序,但是有没有一种简单的方法可以通过组合使用
awk
和/或
sed
命令来实现呢?

我还没有测试过这个;试试看,让我知道它是否有效

awk -F';' '
    $3 == "HC" {
        if (NR > 1) {
            print sum
            sum = 0 }
        next }
    { sum += $3 }
    END { print sum }'

我还没有测试过这个;试试看,让我知道它是否有效

awk -F';' '
    $3 == "HC" {
        if (NR > 1) {
            print sum
            sum = 0 }
        next }
    { sum += $3 }
    END { print sum }'
对于给定的输入:

$ cat infile
HA;HB;HC;HD;HE
a1;b1;14;d;e
HA;HB;HC;HD;HE
a2;b2;28;d;e
HA;HB;HC;HD;HE
a31;b31;44;d;e
a32;b32;07;d;e
HA;HB;HC;HD;HE
a4;b4;0;d;e
HA;HB;HC;HD;HE
a51;b51;32;d;e
a52;b52;0;d;e
a53;b53;5;d;e
HA;HB;HC;HD;HE
a6;b6;10;d;e

$ awk -F';' '/^H.*/{if(f)print s; s=0; f=$3=="HC"}f{s+=$3}END{if(f)print s}' infile
14
28
51
0
37
10
它不需要更多的注意,例如:

$ cat infile2
HA;HB;HC;HD;HE
a1;b1;14;d;e
HA;HB;HC;HD;HE
a2;b2;28;d;e
HA;HB;HC;HD;HE
a31;b31;44;d;e
a32;b32;07;d;e
HA;HB;HC;HD;HE
a4;b4;0;d;e
HA;HB;HD;HD;HE         <---- Say if HC does not found
a51;b51;32;d;e
a52;b52;0;d;e
a53;b53;5;d;e
HA;HB;HC;HD;HE
a6;b6;10;d;e

# find only HC in 3rd column
$ awk -F';' '/^H.*/{if(f)print s; s=0; f=$3=="HC"}f{s+=$3}END{if(f)print s}' infile2
14
28
51
0
10

# Find HD in 3rd column
$ awk -F';' '/^H.*/{if(f)print s; s=0; f=$3=="HD"}f{s+=$3}END{if(f)print s}' infile2
37
$cat infile2
哈血红蛋白;HC;高清;他
a1;b1;14;DE
哈血红蛋白;HC;高清;他
a2;b2;28;DE
哈血红蛋白;HC;高清;他
a31;b31;44;DE
a32;b32;07;DE
哈血红蛋白;HC;高清;他
a4;b4;0;DE
哈血红蛋白;高清;高清;他
对于给定的输入:

$ cat infile
HA;HB;HC;HD;HE
a1;b1;14;d;e
HA;HB;HC;HD;HE
a2;b2;28;d;e
HA;HB;HC;HD;HE
a31;b31;44;d;e
a32;b32;07;d;e
HA;HB;HC;HD;HE
a4;b4;0;d;e
HA;HB;HC;HD;HE
a51;b51;32;d;e
a52;b52;0;d;e
a53;b53;5;d;e
HA;HB;HC;HD;HE
a6;b6;10;d;e

$ awk -F';' '/^H.*/{if(f)print s; s=0; f=$3=="HC"}f{s+=$3}END{if(f)print s}' infile
14
28
51
0
37
10
它不需要更多的注意,例如:

$ cat infile2
HA;HB;HC;HD;HE
a1;b1;14;d;e
HA;HB;HC;HD;HE
a2;b2;28;d;e
HA;HB;HC;HD;HE
a31;b31;44;d;e
a32;b32;07;d;e
HA;HB;HC;HD;HE
a4;b4;0;d;e
HA;HB;HD;HD;HE         <---- Say if HC does not found
a51;b51;32;d;e
a52;b52;0;d;e
a53;b53;5;d;e
HA;HB;HC;HD;HE
a6;b6;10;d;e

# find only HC in 3rd column
$ awk -F';' '/^H.*/{if(f)print s; s=0; f=$3=="HC"}f{s+=$3}END{if(f)print s}' infile2
14
28
51
0
10

# Find HD in 3rd column
$ awk -F';' '/^H.*/{if(f)print s; s=0; f=$3=="HD"}f{s+=$3}END{if(f)print s}' infile2
37
$cat infile2
哈血红蛋白;HC;高清;他
a1;b1;14;DE
哈血红蛋白;HC;高清;他
a2;b2;28;DE
哈血红蛋白;HC;高清;他
a31;b31;44;DE
a32;b32;07;DE
哈血红蛋白;HC;高清;他
a4;b4;0;DE
哈血红蛋白;高清;高清;他
说明:

  • 使用
    cat
  • 使用
    分隔符只取第三列
  • HC
    行替换为
    0;expr 0
    值开始构建
    eval
    -bash表达式,最终生成
    expr 0+14
  • @
    临时替换
    \n
    换行符,以规避可能的BSD
    sed
    限制
  • 将双
    @
    替换为单
    @
    ,以避免空行变成空格并导致
    expr
    爆炸
  • +
    替换
    @
    ,将数字相加
  • 执行命令,但使用
    true | | 0;expr…
    以避免第一行出现保证语法错误
  • 这就产生了:

    true || 0; expr 0 + 14 + 0; expr 0 + 28 + 0; expr 0 + 44 + 07 + 0; expr 0 + 0 + 0; expr 0 + 32 + 0 + 5 + 0; expr 0 + 10
    
    输出如下所示:

    14
    28
    51
    0
    37
    10
    
    这在Bash3.2和MacosElCapitan上进行了测试

    说明:

  • 使用
    cat
  • 使用
    分隔符只取第三列
  • HC
    行替换为
    0;expr 0
    值开始构建
    eval
    -bash表达式,最终生成
    expr 0+14
  • @
    临时替换
    \n
    换行符,以规避可能的BSD
    sed
    限制
  • 将双
    @
    替换为单
    @
    ,以避免空行变成空格并导致
    expr
    爆炸
  • +
    替换
    @
    ,将数字相加
  • 执行命令,但使用
    true | | 0;expr…
    以避免第一行出现保证语法错误
  • 这就产生了:

    true || 0; expr 0 + 14 + 0; expr 0 + 28 + 0; expr 0 + 44 + 07 + 0; expr 0 + 0 + 0; expr 0 + 32 + 0 + 5 + 0; expr 0 + 10
    
    输出如下所示:

    14
    28
    51
    0
    37
    10
    
    这在Bash 3.2和MacOS El Capitan上进行了测试。

    awk解决方案:

    $ awk -F';' '$3=="HC" && p{
        print sum          # print current total
        sum=p=0            # reinitialize sum and p
        next
     }
     $3!="HC"{
        sum=sum+($3+0)     # make sure $3 is converted to integer. sum it up.
        p=1                # set p to 1               
     }                     # print last sum
     END{print sum}' input.txt
    
    输出:

    14
    28
    51
    0
    37
    10
    
    一艘班轮:

    $ awk -F";" '$3=="HC" && p{print sum;sum=p=0;next} $3!="HC"{sum=sum+($3+0);p=1} END{print sum}' input.txt
    
    awk解决方案:

    $ awk -F';' '$3=="HC" && p{
        print sum          # print current total
        sum=p=0            # reinitialize sum and p
        next
     }
     $3!="HC"{
        sum=sum+($3+0)     # make sure $3 is converted to integer. sum it up.
        p=1                # set p to 1               
     }                     # print last sum
     END{print sum}' input.txt
    
    输出:

    14
    28
    51
    0
    37
    10
    
    一艘班轮:

    $ awk -F";" '$3=="HC" && p{print sum;sum=p=0;next} $3!="HC"{sum=sum+($3+0);p=1} END{print sum}' input.txt
    

    请您尝试以下内容,并让我知道这是否有助于您

    awk -F";" '
    /^H/ && $3!="HC"{
      flag="";
      next
    }
    /^H/ && $3=="HC"{
      if(NR>1){
        printf("%d\n",sum)
    };
      sum=0;
      flag=1;
      next
    }
    flag{
      sum+=$3
    }
    END{
      printf("%d\n",sum)
    }
    '   Input_file
    
    输出如下


    请您尝试以下内容,并让我知道这是否有助于您

    awk -F";" '
    /^H/ && $3!="HC"{
      flag="";
      next
    }
    /^H/ && $3=="HC"{
      if(NR>1){
        printf("%d\n",sum)
    };
      sum=0;
      flag=1;
      next
    }
    flag{
      sum+=$3
    }
    END{
      printf("%d\n",sum)
    }
    '   Input_file
    
    输出如下


    这将返回7个零。。但是让我来玩玩这个想法,看看我是否能让它发挥作用。它返回7个零。。但让我来玩玩这个想法,看看我是否能让它发挥作用。