我有一个|分隔文件,其中的每个名称$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
Run Code Online (Sandbox Code Playgroud)
我正在尝试根据现有列向该文件添加一些额外的列。
对于 中每个组的第一次出现$6,我想分别从$2和 中取出相应的值$4并将其添加到$7和 中$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|
Run Code Online (Sandbox Code Playgroud)
对于只有一组,$6我认为我可以应用以下代码,但我不确定如何采用它来获得我想要的结果
awk -F"|" 'NR==1 {if($6==group1179); print $0,$7=$2,$8=$4,$9=$3}' OFS="|" file
Run Code Online (Sandbox Code Playgroud)
输出
name_1|2018-11-28|2018-11-28|81|2018-11-28|group1179|2018-11-28|81|2018-11-28
Run Code Online (Sandbox Code Playgroud)
对于复杂的样本输入,请接受我的歉意。对此的任何领导都将受到高度赞赏。
$ 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
Run Code Online (Sandbox Code Playgroud)
$ ./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
Run Code Online (Sandbox Code Playgroud)
Another option is a two-pass approach where you capture the last instance of each group on the first pass and write the data out on the second, e.g.
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
Run Code Online (Sandbox Code Playgroud)
Example Use/Output
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
Run Code Online (Sandbox Code Playgroud)
With your shown samples, please try following awk code. Written and tested in GNU awk, should work in any version of 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
Run Code Online (Sandbox Code Playgroud)