【问题标题】:transform csv file using awk script使用 awk 脚本转换 csv 文件
【发布时间】:2019-10-08 01:12:13
【问题描述】:

我有如下 csv 文件:

C1, C2,   C3,Cv1,Cv2,Cv3,Cv4 ...  this one can be have longer column
x1, x2 ,x3.1, 1.1, 1.2, 1.3, 1.4
x1, x2, x3.2, 2.1, 2.2, 2.3, 2.4
x1, x2, x3.3, 3.1, 3.2, 3.3, 3.4

我想将此 csv 文件转换为如下:

C1,C2,   C3,CTEXT,XVALUE
x1, x2, x3.1, Cv1 , 1.1
x1, x2, x3.1, Cv2 , 1.2
x1, x2, x3.1, Cv3 , 1.3
x1, x2, x3.1, Cv4 , 1.4
x1, x2, x3.2, Cv1 , 2.1
x1, x2, x3.2, Cv2 , 2.2
x1, x2, x3.2, Cv3 , 2.3
x1, x2, x3.2, Cv4 , 2.4
x1, x2, x3.3, Cv1 , 3.1
x1,x2,x3.3, Cv2 , 3.2
x1,x2,x3.3, Cv3 , 3.3
x1,x2,x3.3, Cv4 , 3.4

下面是我的代码:

#!/bin/bash
awk -F, -v OFS=, '{ if (NR==1)
{ print $1,$2,$3, "CTEXT","XVALUE"
  i=4; while (i < NF) {
   a[i]=$i; i=i+1
  }
  am=NF; next
}
i=4 ; while (i < am) {
  if (i > NF) {print "record "NR" insufficient value" >/dev/stderr
  break}
  print $1,$2,$3,a[i],$i
  i=i+1
  }
if (am <NF) print "record "NR" too many values for text" >/dev/stderr
}' input.csv

当我运行脚本时,它显示错误:

awk:第 2 行附近的语法错误 awk:在 2 号线附近救援


由 Ed Morton 编辑 - 我刚刚通过美化器 (gawk -o- '...') 运行脚本,因此更容易阅读/理解:

{
    if (NR == 1) {
        print $1, $2, $3, "CTEXT", "XVALUE"
        i = 4
        while (i < NF) {
            a[i] = $i
            i = i + 1
        }
        am = NF
        next
    }
    i = 4
    while (i < am) {
        if (i > NF) {
            print("record " NR " insufficient value") > (/dev/) stderr
            break
        }
        print $1, $2, $3, a[i], $i
        i = i + 1
    }
    if (am < NF) {
        print("record " NR " too many values for text") > (/dev/) stderr
    }
}

【问题讨论】:

  • @Amadan Pivot 与转置不同。
  • @Barmar:是的。我的错。我没有注意到数据,认为标题是正确的。
  • 这看起来像一个旧的 awk 错误消息。试试nawk,或gawk/usr/xpg4/bin/awk。 (编辑您的 Q 以显示 uname -srv 的输出)。祝你好运。
  • 请选择一种通用的代码格式并将其用于您的脚本。您现在拥有的某些行上有多个语句和随意的缩进会使您的脚本不必要地难以理解。此外 - awk 支持 for 循环,因此您可以编写类似 for (i=4; i&lt;NF; i++) { foo } 的语句,而不是 i=4; while (i&lt;NF) { foo; i = i + 1 }

标签: bash awk


【解决方案1】:

即使您将 Solaris awk 切换为 gawk 或 nawk,仍然存在 还有些问题。请您尝试以下方法:

awk -F, -v OFS=, '
NR==1 {
    print $1,$2,$3, "CTEXT","XVALUE"
    for (i = 4; i <= NF; i++) a[i]=$i
    am=NF; next
}
{
    if (am < NF) {
        print "record "NR" too many values for text" > "/dev/stderr"
        next
    }
    for (i = 4; i <= am; i++) {
        if (i > NF) {
            print "record "NR" insufficient value" > "/dev/stderr"
            break
        }
        print $1,$2,$3,a[i],$i
    }
}' input.csv
  • 您需要将i 增加到NRam(不是
  • 用引号将/dev/stderr 括起来。
  • 最好使用for 循环而不是while

希望这会有所帮助。

【讨论】:

  • @wina 如果你的意思是same error的消息awk: syntax error near line 2 awk: bailing out near line 2,你首先需要换成其他awk作为@shellter cmets。我上面的代码本身并不能解决错误。
  • @wina 很高兴知道它的工作原理。顺便说一句,令人惊讶的是,尽管您无法运行它,但您几乎接近正确答案。干杯!
【解决方案2】:

类似的东西

$ awk -F, 'BEGIN {OFS=FS} 
           NR==1 {n=split($0,h); 
                  print $1,$2,$3,"CTEXT","XVALUE"; 
                  next} 
           n!=NF {print n<NF?"too many":"not enough"; 
                  exit} 
                 {for(i=4;i<=NF;i++) print $1,$2,$3,h[i],$i}' file

C1,C2,C3,CTEXT,XVALUE
x1,x2,x3.1,Cv1,1.1
x1,x2,x3.1,Cv2,1.2
x1,x2,x3.1,Cv3,1.3
x1,x2,x3.1,Cv4,1.4
x1,x2,x3.2,Cv1,2.1
x1,x2,x3.2,Cv2,2.2
x1,x2,x3.2,Cv3,2.3
x1,x2,x3.2,Cv4,2.4
x1,x2,x3.3,Cv1,3.1
x1,x2,x3.3,Cv2,3.2
x1,x2,x3.3,Cv3,3.3
x1,x2,x3.3,Cv4,3.4

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-23
    • 1970-01-01
    • 2021-04-21
    • 1970-01-01
    • 2021-09-22
    • 2017-06-24
    相关资源
    最近更新 更多