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

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

问题描述:

我有一个CSV日志文件,记录属性HA;HB;HC;HD;HE。以下文件记录了6个条目(由上述标题分隔)。使用Linux命令进行复杂的CSV解析

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

每当有n线HC每个条目记录,我想提取添加n条目。

预期输出上述文件:

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 }' 
+0

这将返回7个零。但让我打一点点这种想法,看看我能得到它的工作。 – kami

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 

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. 采取只使用cut分隔符的;
  3. 第三列与0; expr 0值替换HC线开建eval -worthy bash的表达式,最终产生expr 0 + 14;
  4. 更换\n换行@绕过可能的BSD sed限制
  5. 将双@@替换为单个@,以避免空行变成空格并导致expr炸毁。
  6. @替换为+以将数字相加。
  7. 执行该命令,但使用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 

这是巴蜀3.2和MacOS埃尔卡皮坦测试。

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 

输出如下。

14 
28 
51 
0 
37 
10 

$ awk -F';' '$3=="HC"{if (NR>1) print s; s=0; next} {s+=$3} END{print s}' file 
14 
28 
51 
0 
37 
10