AWK:基于现有列派生字段(创建新列)

时间:2021-07-14 17:06:41

标签: awk

我有一个 | 分隔文件,其中 $1 中的每个名称都分配给 $6 中的一个组。文件按 $5(升序)排序。

name_1|2018-09-28|1801-01-01|22|2018-11-19|group2117
name_1|2018-11-28|2018-11-28|81|2018-11-28|group1179
name_1|2018-09-28|2018-12-18|22|2018-12-14|group2117
name_4|2019-10-09|1801-01-01|22|2019-10-14|group3090
name_4|2019-10-09|2019-10-18|22|2019-10-15|group3090
name_4|2019-10-20|1801-01-01|21|2019-10-20|group3147
name_4|2019-10-20|2019-10-22|21|2019-10-21|group3147
name_11|2020-05-05|1801-01-01|21|2020-05-08|group4457
name_11|2020-05-05|2020-05-18|21|2020-05-18|group4457

我正在尝试根据现有列向该文件添加一些额外的列。

对于$6中每个组的第一次出现,我想从$2$4中取出相应的值并将其添加到$7和{{1 }}, 分别。对于 $8 中每个组的最后一次出现,从 $6 中获取相应的值并将其添加到 $3。所以输出看起来像这样

$9

对于 name_1|2018-09-28|1801-01-01|22|2018-11-19|group2117|2018-09-28|22|2018-12-18 name_1|2018-11-28|2018-11-28|81|2018-11-28|group1179|2018-11-28|81|2018-11-28 name_1|2018-09-28|2018-12-18|22|2018-12-14|group2117| name_4|2019-10-09|1801-01-01|22|2019-10-14|group3090|2019-10-09|22|2019-10-18 name_4|2019-10-09|2019-10-18|22|2019-10-15|group3090| name_4|2019-10-20|1801-01-01|21|2019-10-20|group3147|2019-10-20|21|2019-10-22 name_4|2019-10-20|2019-10-22|21|2019-10-21|group3147| name_11|2020-05-05|1801-01-01|21|2020-05-08|group4457|2020-05-05|21|2020-05-18 name_11|2020-05-05|2020-05-18|21|2020-05-18|group4457| 中的一个组,我认为我可以应用以下代码,但我不确定如何采用它来获得我想要的结果

$6

输出

 awk -F"|" 'NR==1 {if($6==group1179); print $0,$7=$2,$8=$4,$9=$3}' OFS="|" file

对于复杂的样本输入,请接受我的歉意。我们将不胜感激。

3 个答案:

答案 0 :(得分:6)

$ cat tst.sh
#!/usr/bin/env bash

sort -t'|' -k6,6 -k5,5 "${@:--}" |
awk '
    BEGIN { FS=OFS="|" }
    $6 != prev {
        if ( NR > 1 ) {
            prt()
        }
        prev = $6
    }
    { lines[++numLines] = $0 }
    END { prt() }

    function prt(       first,last,i) {
        split(lines[1],first)
        split(lines[numLines],last)

        print lines[1], first[2], first[4], last[3]

        for (i=2; i<=numLines; i++) {
            print lines[i]
        }

        numLines = 0
    }
' |
sort -t'|' -k5,5

$ ./tst.sh file
name_1|2018-09-28|1801-01-01|22|2018-11-19|group2117|2018-09-28|22|2018-12-18
name_1|2018-11-28|2018-11-28|81|2018-11-28|group1179|2018-11-28|81|2018-11-28
name_1|2018-09-28|2018-12-18|22|2018-12-14|group2117
name_4|2019-10-09|1801-01-01|22|2019-10-14|group3090|2019-10-09|22|2019-10-18
name_4|2019-10-09|2019-10-18|22|2019-10-15|group3090
name_4|2019-10-20|1801-01-01|21|2019-10-20|group3147|2019-10-20|21|2019-10-22
name_4|2019-10-20|2019-10-22|21|2019-10-21|group3147
name_11|2020-05-05|1801-01-01|21|2020-05-08|group4457|2020-05-05|21|2020-05-18
name_11|2020-05-05|2020-05-18|21|2020-05-18|group4457

答案 1 :(得分:5)

另一种选择是两遍方法,在第一遍捕获每个组的最后一个实例,然后在第二遍写出数据,例如

awk -F"|" -v OFS="|" '
    NR==FNR { last[$6] = $3; next }
    $6 in seen { print; next }
    { print $0, $2, $4, last[$6]; seen[$6]++ }
' file file

示例使用/输出

name_1|2018-09-28|1801-01-01|22|2018-11-19|group2117|2018-09-28|22|2018-12-18
name_1|2018-11-28|2018-11-28|81|2018-11-28|group1179|2018-11-28|81|2018-11-28
name_1|2018-09-28|2018-12-18|22|2018-12-14|group2117
name_4|2019-10-09|1801-01-01|22|2019-10-14|group3090|2019-10-09|22|2019-10-18
name_4|2019-10-09|2019-10-18|22|2019-10-15|group3090
name_4|2019-10-20|1801-01-01|21|2019-10-20|group3147|2019-10-20|21|2019-10-22
name_4|2019-10-20|2019-10-22|21|2019-10-21|group3147
name_11|2020-05-05|1801-01-01|21|2020-05-08|group4457|2020-05-05|21|2020-05-18
name_11|2020-05-05|2020-05-18|21|2020-05-18|group4457

答案 2 :(得分:5)

对于您显示的示例,请尝试遵循 awk 代码。在 GNU awk 中编写和测试,应适用于 awk 的任何版本。

awk '
BEGIN{ FS=OFS="|" }
!arr1[$6]++{
  arr4[++count]=$6
}
{
  lastVal[$6]=$3
  ++arr3[$6]
  arr2[arr3[$6],$6]=$0
  arr5[arr3[$6],$6]=$2 OFS $4
}
END{
  for(i=1;i<=count;i++){
    for(j=1;j<=arr3[arr4[i]];j++){
      print arr2[arr3[arr4[i]],arr4[i]],(j==1?arr5[arr3[arr4[i]],arr4[i]]:"") (j==1?OFS lastVal[arr4[i]]:"")
    }
  }
}
'  Input_file