如何使用字符长度与AWK分隔列

时间:2018-04-06 19:16:20

标签: bash awk

我有一个数据,没有按照适当的字段分隔符格式化(这是awk擅长)。但是,我所知道的是,数据是固定的宽度。

 NODE     S1           S2           S3           SINT         SEQV    
   1  0.14919     -0.58396E-001-0.71230      0.86149      0.77873     
   2  0.56037E-001 0.23261E-002-0.37154      0.42757      0.40341     
   3  0.52036E-001 0.19762E-001-0.27222      0.32426      0.30939     
   4  0.59765E-001 0.22059E-001-0.24529      0.30505      0.28806     
   5  0.70704E-001-0.51976E-002-0.13862      0.20932      0.18354     
   6  0.11906      0.44607E-001-0.17493      0.29399      0.26474     
   7  0.25540      0.95993E-002-0.43110      0.68650      0.60246     
   8  0.52246E-001-0.47008E-001-0.35167      0.40391      0.36456     
   9  0.32215E-001-0.62291E-001-0.28800      0.32021      0.28497     
  10  0.28072E-001-0.68269E-001-0.28304      0.31111      0.27586     
  11  0.25990E-001-0.78663E-001-0.28626      0.31225      0.27527     
  12  0.26657E-001-0.79217E-001-0.29507      0.32173      0.28400     

预期输出是这样的(其他列中的数字可以具有类似于S2的格式,在数据的其他部分中):

  NODE       S1           S2           S3           SINT         SEQV    
   1    0.14919       -0.58396E-001  -0.71230      0.86149      0.77873     
   2    0.56037E-001   0.23261E-002  -0.37154      0.42757      0.40341     
   3    0.52036E-001   0.19762E-001  -0.27222      0.32426      0.30939     
   4    0.59765E-001   0.22059E-001  -0.24529      0.30505      0.28806     
   5    0.70704E-001  -0.51976E-002  -0.13862      0.20932      0.18354     
   6    0.11906        0.44607E-001  -0.17493      0.29399      0.26474     
   7    0.25540        0.95993E-002  -0.43110      0.68650      0.60246     
   8    0.52246E-001  -0.47008E-001  -0.35167      0.40391      0.36456     
   9    0.32215E-001  -0.62291E-001  -0.28800      0.32021      0.28497     
  10    0.28072E-001  -0.68269E-001  -0.28304      0.31111      0.27586     
  11    0.25990E-001  -0.78663E-001  -0.28626      0.31225      0.27527     
  12    0.26657E-001  -0.79217E-001  -0.29507      0.32173      0.28400     

主要问题是,有时列被空格分隔,有时没有空格(' - '符号占据空间),也就是没有适当的字段分隔符。我发现了一个类似的问题here,但该数据在字段分隔符方面是一致的。根据我的想法,可能有两种方式,

  1. 使用字符长度。例如,从第二行开始,每行的字符数为74或75.
  2. 使用字段宽度:不知道AWK是否可以使用。
  3. 我是AWK的新手,我知道使用其他工具可能非常容易,但我想知道是否可以使用awk分离/提取这些列。我在MacOS的终端中使用awk。

3 个答案:

答案 0 :(得分:4)

您可以FIELDWIDTHS块中指定BEGINsplit fields in a fixed width file in awk

$ cat test
NODE     S1           S2           S3           SINT         SEQV
   1  0.14919     -0.58396E-001-0.71230      0.86149      0.77873
   2  0.56037E-001 0.23261E-002-0.37154      0.42757      0.40341
   3  0.52036E-001 0.19762E-001-0.27222      0.32426      0.30939
   4  0.59765E-001 0.22059E-001-0.24529      0.30505      0.28806
   5  0.70704E-001-0.51976E-002-0.13862      0.20932      0.18354
   6  0.11906      0.44607E-001-0.17493      0.29399      0.26474
   7  0.25540      0.95993E-002-0.43110      0.68650      0.60246
   8  0.52246E-001-0.47008E-001-0.35167      0.40391      0.36456
   9  0.32215E-001-0.62291E-001-0.28800      0.32021      0.28497
  10  0.28072E-001-0.68269E-001-0.28304      0.31111      0.27586
  11  0.25990E-001-0.78663E-001-0.28626      0.31225      0.27527
  12  0.26657E-001-0.79217E-001-0.29507      0.32173      0.28400

$ awk 'BEGIN{ FIELDWIDTHS= "5 13 13 13 13"; OFS="|"}{$1=$1}1' test
NODE |    S1       |    S2       |    S3       |    SINT
   1 | 0.14919     |-0.58396E-001|-0.71230     | 0.86149
   2 | 0.56037E-001| 0.23261E-002|-0.37154     | 0.42757
   3 | 0.52036E-001| 0.19762E-001|-0.27222     | 0.32426
   4 | 0.59765E-001| 0.22059E-001|-0.24529     | 0.30505
   5 | 0.70704E-001|-0.51976E-002|-0.13862     | 0.20932
   6 | 0.11906     | 0.44607E-001|-0.17493     | 0.29399
   7 | 0.25540     | 0.95993E-002|-0.43110     | 0.68650
   8 | 0.52246E-001|-0.47008E-001|-0.35167     | 0.40391
   9 | 0.32215E-001|-0.62291E-001|-0.28800     | 0.32021
  10 | 0.28072E-001|-0.68269E-001|-0.28304     | 0.31111
  11 | 0.25990E-001|-0.78663E-001|-0.28626     | 0.31225
  12 | 0.26657E-001|-0.79217E-001|-0.29507     | 0.32173

$ awk 'BEGIN{ FIELDWIDTHS= "5 13 13 13 13"; OFS="\t"}{$1=$1}1' test
NODE        S1              S2              S3              SINT
   1     0.14919        -0.58396E-001   -0.71230         0.86149
   2     0.56037E-001    0.23261E-002   -0.37154         0.42757
   3     0.52036E-001    0.19762E-001   -0.27222         0.32426
   4     0.59765E-001    0.22059E-001   -0.24529         0.30505
   5     0.70704E-001   -0.51976E-002   -0.13862         0.20932
   6     0.11906         0.44607E-001   -0.17493         0.29399
   7     0.25540         0.95993E-002   -0.43110         0.68650
   8     0.52246E-001   -0.47008E-001   -0.35167         0.40391
   9     0.32215E-001   -0.62291E-001   -0.28800         0.32021
  10     0.28072E-001   -0.68269E-001   -0.28304         0.31111
  11     0.25990E-001   -0.78663E-001   -0.28626         0.31225
  12     0.26657E-001   -0.79217E-001   -0.29507         0.32173

可能需要对这里的任何构成实际字段进行一些调整,但这是它的要点。

答案 1 :(得分:1)

您还可以使用正则表达式解析数字格式,并在每个数字前插入空格:

awk 'NR==1 { print; next } { print gensub(/(-?[0-9]+(\.[0-9]+)?([Ee][+-]?[0-9]+)?)/," \\1", "g") }' FILE

输出:

NODE     S1           S2           S3           SINT         SEQV    
    1   0.14919      -0.58396E-001 -0.71230       0.86149       0.77873     
    2   0.56037E-001  0.23261E-002 -0.37154       0.42757       0.40341     
    3   0.52036E-001  0.19762E-001 -0.27222       0.32426       0.30939     
    4   0.59765E-001  0.22059E-001 -0.24529       0.30505       0.28806     
    5   0.70704E-001 -0.51976E-002 -0.13862       0.20932       0.18354     
    6   0.11906       0.44607E-001 -0.17493       0.29399       0.26474     
    7   0.25540       0.95993E-002 -0.43110       0.68650       0.60246     
    8   0.52246E-001 -0.47008E-001 -0.35167       0.40391       0.36456     
    9   0.32215E-001 -0.62291E-001 -0.28800       0.32021       0.28497     
   10   0.28072E-001 -0.68269E-001 -0.28304       0.31111       0.27586     
   11   0.25990E-001 -0.78663E-001 -0.28626       0.31225       0.27527     
   12   0.26657E-001 -0.79217E-001 -0.29507       0.32173       0.28400  

使用此方法,您不必知道字段数和字段宽度,因此它可以更加强大地防止数据格式更改。

答案 2 :(得分:0)

虽然答案是JNevill& Andriy Makukha他们自己的权利很好,我想使用NAWK(MacOS默认AWK)专门解决问题。我发现“FIELDWIDTHS”只是一个gawk功能Grymoiremachelp

要抓住的是

FS=""

将每个字符视为字段。由于字段宽度相等,因此当知道每列中的字符数时,可以提取每列。例如,如果我想提取第一,第二,第三和最后一列,我可以使用以下代码(如果源数据命名为:test_input.txt):

awk 'BEGIN{FS=""}{print $1$2$3$4"\t"$5$6$7$8$9$10$11$12$13$14$15$16$17$18"\t"$19$20$21$22$23$24$25$26$27$28$29$30$31"\t"$59$60$61$62$63$64$65$66$67$68$69$70}' test_input.txt

输出:

NODE         S1             S2             SEQV    
   1      0.14919       -0.58396E-001   0.77873     
   2      0.56037E-001   0.23261E-002   0.40341     
   3      0.52036E-001   0.19762E-001   0.30939     
   4      0.59765E-001   0.22059E-001   0.28806     
   5      0.70704E-001  -0.51976E-002   0.18354     
   6      0.11906        0.44607E-001   0.26474     
   7      0.25540        0.95993E-002   0.60246     
   8      0.52246E-001  -0.47008E-001   0.36456     
   9      0.32215E-001  -0.62291E-001   0.28497     
  10      0.28072E-001  -0.68269E-001   0.27586     
  11      0.25990E-001  -0.78663E-001   0.27527     
  12      0.26657E-001  -0.79217E-001   0.28400

这是一个简单但有些简单的解决方案,但对于大数据来说,它现在对我来说很有用。任何进一步的改进都将受到欢迎......