使用 awk 将数据附加到类似的行

使用 awk 将数据附加到类似的行

我的文件中的数据如下所示:

field11|field12|field13
field11|field12|field23
field11|field32|field33
field41|field42|field43
field41|field52|field43
field41|field62|field63

正如你所看到的,我有 2 个 id field11,并且field41我希望它们只出现一次,如下所示:

field11|{'field12','field32'}|field13
field41|{'field42','field52','field62'}|field43

我希望第三个字段与该 id 的第一次出现相同。每个 id($1) 都有不同的 $3,而第一个或第一个和第二个字段保持相同。但我需要打印该 id 第一行的内容。如示例所示,我们打印的是 field13 而不是 field23。

我正在尝试用awk/来实现这一点sed。我知道一个解决方案可以使用 shell 中的基本循环来实现此目的。但我需要在awk或一些类似的工具中执行此操作。

答案1

一个稍长(但希望易于理解)的awk解决方案:

BEGIN       { FS = OFS = "|" }

function output() {
    if (FNR == 1) return
    data = ""
    for (i in col2) {
        qi   = sprintf("'%s'", i);
        data = (data == "" ? qi : data "," qi)
    }
    print col1, sprintf("{%s}", data), col3
}

$1 == col1 && !($2 in col2) { col2[$2] }

$1 != col1    {
    output()
    col1 = $1; col3 = $3
    delete col2; col2[$2]
}

END { output() }

BEGIN块只是将输入和输出字段分隔符设置为|

该函数将获取(第一列中的 ID)、(第二列中的唯一数据数组)和(第三列中该特定 ID 的第一个数据项)output()中收集的数据并将其输出。它迭代 中的键,单独引用它们并将它们之间用逗号添加到字符串变量 中。然后它打印, (在大括号内)和。col1col2col3col2datacol1datacol3

当我们在第二列中找到该特定 ID 之前从未见过的条目时,就会执行下一个块。它只是将第二列添加为 中的键col2

当我们在第一列中找到新 ID 时,执行后面的块。它调用output()并重置收集的变量以开始收集该新 ID 的数据。

END块中,我们调用output()输出最后一个ID的数据。

该程序不会尝试将整个文件立即存储在内存中,而是要求数据在第一列上排序。

在提供的数据上运行它:

$ awk -f script.awk file
field11|{'field12','field32'}|field13
field41|{'field42','field62','field52'}|field43

答案2

Perl 的一些粗糙之处:

perl -F'\|' -lane '
    $f2{ $F[0] }{ $F[1] } = 1;
    $f3{ $F[0] } = $F[2] if not exists $f3{ $F[0] }; 
  } END {
    for $key (sort keys %f2) {
        printf "%s|{%s}|%s\n", 
            $key, 
            join(",", map {chr(39) . $_ . chr(39)} sort keys %{$f2{$key}}), 
            $f3{$key};
    }
' file

前两行使用关联数组累积数据。
然后 END 块循环处理数据、格式和打印。

相关内容