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

时间:2017-09-27 00:42:46

标签: csv awk sed command-line

我有一个记录属性HA;HB;HC;HD;HE的CSV日志文件。以下文件记录了6个条目(由上面的标题分隔)。

我想提取每个条目的第3个属性(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

每当条目记录nHC时,我想提取n条目的添加内容。

上述文件的预期输出:

14
28
51
0
37
10

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

6 个答案:

答案 0 :(得分:1)

我没有测试过这个;尝试一下,让我知道它是否有效。

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

答案 1 :(得分:1)

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

答案 2 :(得分:0)

awk -F';' '/^H.*/{if(f)print s;s=0;f=$3=="HC"}f{s+=$3}END{if(f)print s}' infile

对于给定的输入:

$ 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

答案 3 :(得分:0)

eval "true || $(cat data.csv|cut -d ";" -f3 |sed -e s/"HC"/"0; expr 0"/g |tr '\n' '@'|sed -e s/"@@"/""/g|sed -e s/"@"/" + "/g)"

<强>解释

  1. 使用cat
  2. 获取文件内容
  3. 使用cut
  4. ;分隔符仅使用第三列
  5. HC行替换为0; expr 0个值,以开始构建eval - 有价值的bash表达式,最终产生expr 0 + 14;
  6. 暂时用\n替换@个换行符,以规避可能的BSD sed限制
  7. @@替换为单@,以避免空行变成空格并导致expr炸弹。
  8. @替换为+,将这些数字加在一起。
  9. 执行命令,但使用true || 0; expr ...以避免第一行有保证的语法错误。
  10. 创造了这个:

    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上测试的。

答案 4 :(得分:0)

请您试着跟随并告诉我这是否对您有帮助。

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

输出如下。

14
28
51
0
37
10

答案 5 :(得分:0)

$('#link').remove();