在两个文件中查找包含常用单词的行

时间:2016-06-11 12:44:37

标签: perl unix sed

档案1

  • 的apache2-devel的-2.0.59-5.2
  • 的apache2-DOC-2.0.59-5.2
  • 的apache2-示例的页面-2.0.59-5.2
  • 的apache2-mod_perl的-2.0.3.99-1.1
  • utempter-32位-9-200407011229
  • 的apache2-工人2.0.59-5.2
  • 的apache2-prefork的-2.0.59-5.2

文件2

  • 的apache2-devel的-2.2.12-1.38.2
  • 的apache2-DOC-2.2.12-1.40.1
  • 的apache2-示例的页面-2.2.12-1.40.1
  • 的apache2-mod_perl的-2.0.4-40.19
  • utempter-32位-0.5.5-106.20.1
  • 的apache2-工人2.0.59-5.2
  • 的apache2-prefork的-2.0.59-5.2

我想要具有不同版本的软件列表。例如,除了最后两个之外的所有版本都有不同的版本。订单可能不同。

我不知道该怎么办。

4 个答案:

答案 0 :(得分:3)

我认为Borodin通过对你的问题的评论让我走上了正确的方向:你展示的文件似乎是rpm -qa的输出。

样品:

$ rpm -qa | head -5
aaa_skel-2006.5.19-0.3
glibc-i18ndata-2.4-31.30
release-notes-sles-10-43.51
sles-stor_evms_en-10.1-0.10
yast2-schema-2.13.5-0.13

有一些rpm的开关会影响该输出,即--queryformat选项。有关详细信息,请参阅此处http://www.rpm.org/max-rpm/s1-rpm-query-parts.html(向下滚动到"标记"部分)。

使用该开关,可以定义输出格式,并使用自定义字符串分隔包名称,版本和版本号:

$ rpm -qa --queryformat '%{NAME}\t%{VERSION}\t%{RELEASE}\n' | head -5
aaa_skel    2006.5.19   0.3
glibc-i18ndata  2.4 31.30
release-notes-sles  10  43.51
sles-stor_evms_en   10.1    0.10
yast2-schema    2.13.5  0.13

我在这里使用了一个标签\t,但任何其他独特的字符/字符串都可以使用。

如果您可以通过这种方式重新编写文件列表,那么更容易区分名称和数字,因为简单split(/\t/)会这样做。< / p>

我知道这不是您问题的完整答案,但如果您能确定rpm -qa --queryformat是否适合您,我会修改它。 如果我完全错了,请告诉我,我将删除我的帖子。

答案 1 :(得分:1)

这是我快速放在一起的东西,至少应该给你一个起点。我欺骗了像"Ramzi"这样不太容易解析的条目。

请注意,如果您有非常大的文件,您可能需要采用不同的方法,因为第一个文件完全插入内存。

utempter-32bit-9-200407011229

输出:

use warnings;
use strict;

open my $fh1, '<', 'f1.txt' or die $!;
open my $fh2, '<', 'f2.txt' or die $!;

my %f1; 

while (<$fh1>){
    chomp;
    next if ! check($_); 
    my ($app, $ver) = separate($_);
    next if ! $app;
    $f1{$app} = $ver;
}

while (<$fh2>){
    chomp;
    next if ! check($_); 
    my ($app, $ver) = separate($_);
    next if ! $app;

    if (exists $f1{$app}){
        if ($ver ne $f1{$app}){
            print "$app version differs\n";
        }
    } 
} 

sub separate { 
    my $line = shift; 
    if (my ($app, $ver) = $line =~ /(.*?)-(\d+\..*)/){
        return ($app, $ver);
    }
}
sub check {
    my $line = shift;
    if ($line !~ /\./){
        print "* can't parse $line, check manually\n";
        return 0;
    }
    return 1;
}

答案 2 :(得分:1)

这个程序似乎可以满足您的需求

将软件名称与其版本号分开是任意的,因此最好的猜测是我使用了仅包含十进制数字和点.作为版本号的所有字段,以及之前的所有内容作为名称< / p>

use strict;
use warnings 'all';

use Sort::Naturally 'ncmp';

my @files = qw/ file1.txt file2.txt /;

my @info = map { read_file_info($_) } @files;

my @software = do {
    my %sw;
    ++$sw{$_} for map { keys %$_ } @info;
    sort keys %sw;
};

for my $sw ( @software ) {

    print "$sw:\n";

    my @versions = map { $_->{$sw} // '' } @info;

    if ( $versions[0] eq $versions[1] ) {
        printf "    Version %s in both files\n", $versions[0];
    }
    else {
        for my $i ( sort { ncmp($versions[$a], $versions[$b]) } 0 .. $#files ) {
            printf "    %s in %s\n",
                $versions[$i] ? "Version $versions[$i]" : "Doesn't appear",
                $files[$i];
        }
    }

    print "\n";
}


sub read_file_info {
    my ($file) = @_;

    use autodie;

    open my $fh, '<', $file;

    my %info;

    while ( my $line = <$fh> ) {
        next unless /\S/;

        my ( $software, $version ) = split_name_vn($line);
        $info{$software} = $version;
    }

    \%info;
}


sub split_name_vn {
    my ($s) = @_;
    return ( $1, $2 ) if $s =~ /^(.+?)-([\d.-]+)$/;
    return;
}

输出

apache2-devel:
    Version 2.0.59-5.2 in file1.txt
    Version 2.2.12-1.38.2 in file2.txt

apache2-doc:
    Version 2.0.59-5.2 in file1.txt
    Version 2.2.12-1.40.1 in file2.txt

apache2-example-pages:
    Version 2.0.59-5.2 in file1.txt
    Version 2.2.12-1.40.1 in file2.txt

apache2-mod_perl:
    Version 2.0.3.99-1.1 in file1.txt
    Version 2.0.4-40.19 in file2.txt

apache2-prefork:
    Version 2.0.59-5.2 in both files

apache2-worker:
    Version 2.0.59-5.2 in both files

utempter-32bit:
    Version 0.5.5-106.20.1 in file2.txt
    Version 9-200407011229 in file1.txt

答案 3 :(得分:0)

$ cat tst.awk
match($0,/[-0-9.]+$/) {
    pkg = substr($0,1,RSTART-1)
    ver = substr($0,RSTART+1)
}
NR==FNR { p2v[pkg]=ver; next }
ver != p2v[pkg]

$ awk -f tst.awk file1 file2
apache2-devel-2.2.12-1.38.2
apache2-doc-2.2.12-1.40.1
apache2-example-pages-2.2.12-1.40.1
apache2-mod_perl-2.0.4-40.19
utempter-32bit-0.5.5-106.20.1