【问题标题】:Merge multiple columns from different files with a partial match via awk通过 awk 将来自不同文件的多个列与部分匹配合并
【发布时间】:2022-10-23 19:14:32
【问题描述】:

我有两个文件,A 和 B,列用 \ 分隔。
柱子2文件的一个正是相同的作为列1文件的.
我想合并这两个文件,保持文件 B 相同,添加一个基于两个文件之间相同字段的新列,以及文件 A 的第 1 列和文件 B 的第 2 列之间的部分匹配。

通过部分匹配,我的意思是这样的:

File A (column 1) File B (column 2) A=B?
A A? True
A Asd True
B B True
C c True
C CA True
D A False

如果价值观文件 A 中的第 1 列和第 2 列相同,它们必须是添加到文件 B;

档案 A
A\2022.10.10\注意
A\2022.10.10\注b
B\2022.10.14\注c
A\2022.10.14\注d
C\2022.10.15\注e

文件 B
2022.10.10\A?
2022.10.14\B?
2022.10.14\a
2022.10.15\C
2022.10.15\D

期望的输出
2022.10.10\A?\注a;注b\
2022.10.14\B?\注c\
2022.10.14\a\注d\
2022.10.15\C\注e\
2022.10.15\D\

我怎样才能用 awk 做到这一点?

【问题讨论】:

  • 为什么文件 B 中的“note d”没有与“note a”和“note b”合并,即为什么“A”==“A?”但在所需的输出中不是“A”==“a”,但在表中说明“C”==“c”是真的?您能否解释匹配是否区分大小写,这意味着部分匹配是否会发生在两个文件列的大写值上? aka 是upper(file2_col2_value).startswith(upper(file1_col1_value) 的标准吗?
  • 记录是否定义为每个文件中的行位置或日期字段?
  • @LarsFischer 如果以令人困惑的方式解释,我深表歉意。我会尽量说得更清楚。是的,这两个文件都区分大小写。仅当起点相同时才会发生部分匹配。例如:[FileA = US/2022.10.22/note a] [FileB = 2022.10.22/USA] 然后是 [desired output = 2022.10.22/USA/note a] 因为文件 A 的第 1 列包含在第 2 列中文件 B 并且它们都以完全相同的方式开始。这也是为什么将文件 A(注 a)的第 3 列添加到文件 B 的原因。
  • @Forky考虑到所需的输出:为什么文件A的“A\2022.10.14\note d”行的“note d”和键“A”没有出现在同样属于“note a;note b”之后的所需输出中键“A”?两个文件中看起来像日期的列是怎么回事?

标签: linux awk


【解决方案1】:

awk 脚本可能会根据您的要求的详细信息(例如,键是否区分大小写)起作用。

像这样的 awk 脚本可能会起作用:

function make_key(k) 
{
    # either return k or an uppercase version for case-insensitive keys
    # return k;
    return toupper(k);
}

BEGIN { 
    FS="\";
}

NR==FNR {
    key=make_key($2 "\" $1);
    if( key in notes){
        notes[key]=notes[key] ";" $3
    }
    else {
        notes[key]=$3
    }
        
}

NR!=FNR {
    for(k in notes){
         pos=index(make_key($0),k);
         if(pos==1){
            printf "%s%s%s%s
",  $0, FS, notes[k], FS;
            next;
         }
    }
    print $0 FS;
}

你会像这样使用它:

awk -f script.awk file_A file_B

在函数 make_key 中,您可以通过返回 k 或大写版本来配置区分大小写。

NF==FNR 块在读取第一个文件 (file_A) 期间使用,这里的注释存储在由第二列和第一列组成的键下。如果密钥已经存在,则附加注释。

NF!=FNR 块中读取第二个文件(file_B)。在这里,如果 file_B 的行以键开头,我们通过比较每个键来打印 file_b 的行和匹配的注释。如果没有键匹配,则仅打印 file_B 行。

BEGIN 块只是设置字段分隔符。

【讨论】:

    【解决方案2】:

    要处理第一个文件,我们可以使用条件NR==FNR。在第一个文件处理过程中,我使用了两个哈希表,即pattern_ht 以小写形式存储第 1 列的值,note_ht 存储第 3 列的值。由于日期字符串本身不是唯一的用作键,因此我们将使用第 2 列和第 3 列的串联作为两个哈希表的键。

    在处理第二个文件时,首先检查日期字符串是否与执行密钥字符串拆分后的第 1 列完全匹配。如果匹配,则在转换为小写后将第 2 列与pattern_ht 值进行部分匹配。如果匹配并且这是第一个匹配,则记录third_col 值。如果它已经有另一个值,用“;”附加到它。最后,相应地显示:

    awk -F'' 'NR==FNR {pattern_ht[$2";"$3] = tolower($1); note_ht[$2";"$3] = $3; next} 
    {third_col="";
    for (key in pattern_ht) {
            split(key,date_str,";");
            if (date_str[1] == $1) {
                    if (tolower($2) ~ pattern_ht[key]) { 
                            if (length(third_col) == 0) 
                                    third_col = note_ht[key] 
                            else 
                                    third_col = third_col ";" note_ht[key]
                            }
            }
    }
    if (length(third_col) != 0)
            print $1"\"$2"\"third_col"\"
    else
            print $1"\"$2"\"
    }' fileA fileB
    

    这是输出:

    2022.10.10A?
    ote a;note b
    2022.10.14B?
    ote c
    2022.10.14
    ote d
    2022.10.15C
    ote e
    2022.10.15D
    

    【讨论】:

      猜你喜欢
      • 2019-04-19
      • 2015-02-11
      • 2018-08-24
      • 2013-01-09
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 2016-12-21
      相关资源
      最近更新 更多