如何使用perl或*nix命令对ip地址进行排序并有效地合并两个文件?

如何使用perl或*nix命令对ip地址进行排序并有效地合并两个文件?,perl,unix,sorting,merge,Perl,Unix,Sorting,Merge,(*)这个问题应该在perl或任何*nix命令中解决 我正在处理一个程序和效率问题。文件1包括ip地址和一些其他数据: index ipsrc portsrc ip dest port src 8 128.3.45.10 2122 169.182.111.161 80 (same ip src and dst) 9 128.3.45.10 2123 169.182.111.161 22 (same ip src and dst) 10 128.3.45.10 2124 169.

(*)这个问题应该在perl或任何*nix命令中解决

我正在处理一个程序和效率问题。文件1包括ip地址和一些其他数据:

index ipsrc     portsrc  ip dest     port src
8 128.3.45.10 2122 169.182.111.161 80 (same ip src and dst)
9 128.3.45.10 2123 169.182.111.161 22 (same ip src and dst)
10 128.3.45.10 2124 169.182.111.161 80 (same ip src and dst)
19 128.3.45.128 62256 207.245.43.126 80
和其他文件2类似(文件1和文件2的顺序不同)

1-在第二列中使用IP地址对文件1排序,在第一列中使用IP地址对文件2排序

2-将文件1的第1、第3和第5列与文件2合并

我需要创建一个新文件,该文件将显示:

128.3.45.10 ioc-sea-lm 169.182.111.161 microsoft-ds 0 0 3 186 3 186 --> 2122 80 8
128.3.45.10 hypercube-lm 169.182.111.161 https 0 0 3 186 3 186 --> 2123 22 9
128.3.44.112 pay-per-view 148.184.171.6 netbios-ssn 0 0 3 186 3 186 --> * * *
128.3.45.12 cadabra-lm 148.184.171.6 microsoft-ds 0 0 3 186 3 186 --> * * *

基本上会添加端口号和索引号。

表面上看,它似乎是
排序
加入
的明显应用:

sort -k2 file1 > sorted.1
sort -k1 file2 > sorted.2
join -1 2 -2 1 -a 2 -e '*' \
    -o 2.1,2.2,2.3,2.4,2.5,2.6,2.7,2.8,2.9,2.10,1.1,1.3,1.5 \
    sorted.1 sorted.2
然而,这项研究的结果是:

128.3.44.112 pay-per-view 148.184.171.6 netbios-ssn 0 0 3 186 3 186 * * *
128.3.45.10 hypercube-lm 169.182.111.161 https 0 0 3 186 3 186 8 2122 80
128.3.45.10 ioc-sea-lm 169.182.111.161 microsoft-ds 0 0 3 186 3 186 8 2122 80
128.3.45.10 hypercube-lm 169.182.111.161 https 0 0 3 186 3 186 9 2123 22
128.3.45.10 ioc-sea-lm 169.182.111.161 microsoft-ds 0 0 3 186 3 186 9 2123 22
128.3.45.10 hypercube-lm 169.182.111.161 https 0 0 3 186 3 186 10 2124 80
128.3.45.10 ioc-sea-lm 169.182.111.161 microsoft-ds 0 0 3 186 3 186 10 2124 80
128.3.45.12 cadabra-lm 148.184.171.6 microsoft-ds 0 0 3 186 3 186 * * *
关闭,但没有骰子:问题是IP地址128.3.45.10在file1中出现三次,在file2中出现两次,
join
因此创建了6行(笛卡尔乘积)


这似乎是一个需要在使用条目时使用/销毁条目的应用程序。这表明我们需要使用Perl(或类似的脚本语言)。因此,我们不清楚是否需要对文件1进行排序;我们需要读取file1并创建一个结构,其中哈希键位于IP地址(字段2),其中键指向一个字符串数组,每个记录只包含所需的三个字段(1、3、5)

然后我们依次处理file2,在散列中找到匹配的IP地址,并使用数组中的第一个条目——如果没有这样的条目,则使用星号。我们也可以添加问题中要求的“
-->

这导致了一个相当简单的程序:

#!/usr/bin/env perl

use strict;
use warnings;

my %file1 = read_file1("file1");

sub read_file1
{
    my($file) = @_;
    open my $fh, '<', $file or die "Failed to open $file for reading ($!)";
    my %file1;
    while (my $line = <$fh>)
    {
        my @fields = split / /, $line;
        my $ip = $fields[1];
        $file1{$ip} = [ ] unless defined $file1{$ip};
        push @{$file1{$ip}}, "$fields[0] $fields[2] $fields[4]";
    }
    return %file1;
}

my $file2 = "file2";
open my $f2, '<', $file2 or die "Failed to open $file2 for reading ($!)";

while (my $line = <$f2>)
{
    chomp $line;
    my($ip) = ($line =~ m/^(\S+) /);
    my $aux = "* * *";
    if (defined $file1{$ip})
    {
        $aux = shift @{$file1{$ip}};
        delete $file1{$ip} if scalar @{$file1{$ip}} == 0;
    }
    print "$line --> $aux\n";
}

看不到排序-因此它相当有效。

您对内存效率或CPU/时间效率感兴趣吗?第二个文件的格式是什么?前两行似乎重复了相同的源IP和目标IP,但主机名不同。这似乎是个错误?如果没有,那么将更难(不可能?)唯一地映射回第一个文件。@jimtut,file2具有相同的ip地址,但只解码端口号。因此,我认为使用src ip地址对两个文件进行排序将获得逐行匹配,然后我可以合并它并创建输出文件。您可以对第一个文件进行如下排序:cat file1 | awk'{print$2”“$3”“$4”“$5”“$1}'| sort>file 1A但是,我可能缺少一些东西,因为我找不到任何方法将第二个文件的某些行(如“128.3.45.10 ioc sea lm…”)唯一地绑定到第一个文件的任何行。由于IP地址在每个文件中出现多次,如何停止“128.3.45.10 ioc sea lm”以匹配到第一个文件的第二行(端口2123,而不是端口2122)?由于虚线IP地址表示是32位值的表示,因此可以对IP进行数字排序,将它们转换为32位:ip32=ip1*256*256*256+ip2*256*256+ip3*256+ip4。然后可以将32位值转换回点IP。这将允许对IP地址进行正确排序(128.3.45.12将在128.3.45.10之后,而不是在128.3.45.112之后)。感谢分享您的时间。ip地址可以排序为:sort-n-t-K1,1-K2,2-K3,3-K4,4@mbaitoff,@berkay:是的,如果需要的话,有很多方法可以对输出进行排序。问题中请求的输出按字母数字排序;它也是输入数据的顺序。
#!/usr/bin/env perl

use strict;
use warnings;

my %file1 = read_file1("file1");

sub read_file1
{
    my($file) = @_;
    open my $fh, '<', $file or die "Failed to open $file for reading ($!)";
    my %file1;
    while (my $line = <$fh>)
    {
        my @fields = split / /, $line;
        my $ip = $fields[1];
        $file1{$ip} = [ ] unless defined $file1{$ip};
        push @{$file1{$ip}}, "$fields[0] $fields[2] $fields[4]";
    }
    return %file1;
}

my $file2 = "file2";
open my $f2, '<', $file2 or die "Failed to open $file2 for reading ($!)";

while (my $line = <$f2>)
{
    chomp $line;
    my($ip) = ($line =~ m/^(\S+) /);
    my $aux = "* * *";
    if (defined $file1{$ip})
    {
        $aux = shift @{$file1{$ip}};
        delete $file1{$ip} if scalar @{$file1{$ip}} == 0;
    }
    print "$line --> $aux\n";
}
128.3.45.10 ioc-sea-lm 169.182.111.161 microsoft-ds 0 0 3 186 3 186  --> 8 2122 80
128.3.45.10 hypercube-lm 169.182.111.161 https 0 0 3 186 3 186 --> 9 2123 22
128.3.44.112 pay-per-view 148.184.171.6 netbios-ssn 0 0 3 186 3 186 --> * * *
128.3.45.12 cadabra-lm 148.184.171.6 microsoft-ds 0 0 3 186 3 186 --> * * *