如何合并两个 CSV 文件但仅合并第二个文件匹配的部分?

如何合并两个 CSV 文件但仅合并第二个文件匹配的部分?

我有 2 个 CSV 文件:

对象文件:

IP,MASK,DESCRIPTION
10.10.3.94,255.255.255.255,Rob
10.10.3.95,255.255.255.255,Mark
10.10.3.96,255.255.255.255,John

服务文件:

DESCRIPTION,OrgIP,Service
Rob,1.1.1.1,Purple
John,2.2.2.2,Green
Mark,3.3.3.3,Yellow

对象文件有 3000 行,服务文件有大约 500 行。

我想创建一个新文件,其中包含服务中的所有行,并在描述中找到匹配项的位置添加对象字段。因此所需的输出将如下所示:

DESCRIPTION,OrgIP,Service,IP,MASK
Rob,1.1.1.1,Purple,10.10.3.94,255.255.255.255
John,2.2.2.2,Green,10.10.3.96,255.255.255.255
Mark,3.3.3.3,Yellow,10.10.3.95,255.255.255.255

答案1

如果你的系统上安装了 sqlite3 和 python,你可以使用这个http://www.sqlet.com/

相关的 SQL 命令是:

./sqlet.py -d',' -A file1.txt -B file2.txt 'select A3,B2,B3,A1,A2 from A LEFT JOIN B ON A3=B1;' | sqlite3

这要求您从这两个文件中删除标题。sqlet 脚本必须提取到这两个文件所在的同一文件夹中,或进行相应修改。

我在你的示例摘录上尝试了它。它有效:

bruni@bruni-Inspiron-5547:~/Downloads$ cat file1.txt
10.10.3.94,255.255.255.255,Rob
10.10.3.95,255.255.255.255,Mark
10.10.3.96,255.255.255.255,John
bruni@bruni-Inspiron-5547:~/Downloads$ cat file2.txt
Rob,1.1.1.1,Purple
John,2.2.2.2,Green
Mark,3.3.3.3,Yellow
bruni@bruni-Inspiron-5547:~/Downloads$ ./sqlet.py -d',' -A file1.txt -B file2.txt 'select A3,B2,B3,A1,A2 from A LEFT JOIN B ON A3=B1;' | sqlite3
Rob,1.1.1.1,Purple,10.10.3.94,255.255.255.255
Mark,3.3.3.3,Yellow,10.10.3.95,255.255.255.255
John,2.2.2.2,Green,10.10.3.96,255.255.255.255

答案2

使用join

join --header -t, -11 -23 -a1 <(awk 'NR > 1 {print | "sort -t, -k1"; next} 1' services) <(awk 'NR > 1 {print | "sort -t, -k3"; next} 1' objects)
join --header -t, -11 -23 -a1 <(
    awk '
        NR > 1 {
            print |
                "sort -t, -k1";
            next
        }
        1
    ' services
) <(
    awk '
        NR > 1 {
            print |
                "sort -t, -k3";
            next
        }
        1
    ' objects
)
  • --header:将每个文件的第一行视为字段标题,打印它们而不尝试将它们配对
  • -t,:设置,为输入和输出字段分隔符
  • -11:连接到字段 #1services
  • -23:连接到字段 #3objects
  • -a1: 还打印不成对的行services
  • <(awk 'NR > 1 {print | "sort -t, -k1"; next} 1' services)services1除标题之外的列排序
  • <(awk 'NR > 1 {print | "sort -t, -k3"; next} 1' objects)objects3除标题之外的列排序
% cat objects 
IP,MASK,DESCRIPTION
10.10.3.94,255.255.255.255,Rob
10.10.3.95,255.255.255.255,Mark
10.10.3.96,255.255.255.255,John
% cat services 
DESCRIPTION,OrgIP,Service
Rob,1.1.1.1,Purple
John,2.2.2.2,Green
Mark,3.3.3.3,Yellow
% join --header -t, -11 -23 -a1 <(awk 'NR > 1 {print | "sort -t, -k1"; next} 1' services) <(awk 'NR > 1 {print | "sort -t, -k3"; next} 1' objects)
DESCRIPTION,OrgIP,Service,IP,MASK
John,2.2.2.2,Green,10.10.3.96,255.255.255.255
Mark,3.3.3.3,Yellow,10.10.3.95,255.255.255.255
Rob,1.1.1.1,Purple,10.10.3.94,255.255.255.255

答案3

如果文件不是太大,怎么样awk

$ awk -F, 'NR==FNR {a[$1]=$2 FS $3 FS $4; next} $3 in a {OFS=","; print $3,a[$3],$2}' services objects
DESCRIPTION,OrgIP,Service,IP,MASK
Rob,1.1.1.1,Purple,10.10.3.94,255.255.255.255
Mark,3.3.3.3,Yellow,10.10.3.95,255.255.255.255
John,2.2.2.2,Green,10.10.3.96,255.255.255.255

答案4

你可以做:

join -t, -a2 -11 -23 <(head -1 f1.txt; tail -n +2 f1.txt | \
         sort -t, -k1,1) <(head -1 f2.txt; tail -n +2 f2.txt | sort -t, -k3,3)
  • <()是进程替换语法,bash将用文件描述符替换它,其中包含命令的输出作为内容

  • head -1 f1.txt; tail -n +2 f2.txt | sort -t, -k1,1sort第一个文件的第一个字段从第二行添加到其余行,并将第一行添加到顶部,以便我们可以使用它join。 同样适用于根据f2.txt字段为三。sort

  • join将仅将的第一个字段f1.txt和第三个字段f2.txt作为公共字段加入。

例子:

$ cat f1.txt 
DESCRIPTION,OrgIP,Service
Rob,1.1.1.1,Purple
John,2.2.2.2,Green
Mark,3.3.3.3,Yellow

$ cat f2.txt 
IP,MASK,DESCRIPTION
10.10.3.94,255.255.255.255,Rob
10.10.3.95,255.255.255.255,Mark
10.10.3.96,255.255.255.255,John

$ join -t, -11 -23 <(head -1 f1.txt; tail -n +2 f1.txt | sort -t, -k1,1) <(head -1 f2.txt; tail -n +2 f2.txt | sort -t, -k3,3)
DESCRIPTION,OrgIP,Service,IP,MASK
John,2.2.2.2,Green,10.10.3.96,255.255.255.255
Mark,3.3.3.3,Yellow,10.10.3.95,255.255.255.255
Rob,1.1.1.1,Purple,10.10.3.94,255.255.255.255

相关内容