Mam kilka plików w folderze zawierającym tekst (alfabet, cyfry, symbol itp.). Chcę znaleźć linie, które nie są obecne we wszystkich plikach tj. Jeśli linia jest obecna we wszystkich plikach tekstowych, musi być wykluczona. Jeśli linia jest obecna tylko w 1 lub na maksymalnych plikach N-1, musi być włączony do scalonego pliku z nazwą wszystkich plików, w których jest obecny.

PS: Pliki nie są identyczne, mogą mieć mniej więcej liczbę linii. Linie obecne we wszystkich plikach (niezależnie od ich lokalizacji) muszą być wykluczone.

Tak więc jako przykład:

FILE1:
<abc> 123
$def 456$

FILE2:
$def 456$
ghi 789

FILE3:
$def 456$
ghi 789

. . .

MERGED FILE:
<abc> 123 ==> FILE1
ghi 789 ==> FILE2, FILE3
-3
Andy_Jake 25 czerwiec 2017, 23:15

3 odpowiedzi

Najlepsza odpowiedź

Merge.pl.

my(%file,%line,@f);
chomp, ++$file{$ARGV}, ++$line{$_}{$ARGV} while <>;
(@f=keys(%{$line{$_}}))==keys(%file) or print "$_ ==> ".join(",",sort@f)."\n"
    for sort keys %line;

Następnie uruchomić:

perl merge.pl dir/FILE*


Rateled Perl Code.

my (%file, %line);

while ( <> ) {
    chomp;
    ++$file{$ARGV};
    ++$line{$_}{$ARGV};
}

for my $key ( sort keys %line ) {

    my @f = keys %{ $line{$key} };
    
    if ( @f < keys %file ) {
        print "$_ ==> ", join(",", sort @f), "\n";
    }
}
1
Community 20 czerwiec 2020, 09:12

Oto przykład w Perlu:

use feature qw(say);
use strict;
use warnings;

my $num_files = 0;
my %lines;
for my $fn ( <FILE*> ) {
    open ( my $fh, '<', $fn ) or die "Could not open file '$fn': $!";
    while ( my $line = <$fh> ) {
        chomp $line;
        next if $line =~ /^\s*$/;
        push @{ $lines{$line} }, $fn;
    }
    close $fh;
    $num_files++;
}

for my $line (keys %lines) {
    my @files = @{ $lines{$line} };
    if ( @files < $num_files ) {
        say $line, ' ==> ', join ",", @files;
    }
}

Wyjście :

ghi 789 ==> FILE2,FILE3
<abc> 123 ==> FILE1
0
Håkon Hægland 26 czerwiec 2017, 06:25

Z GNU awk do prawdziwych multimencyjnych tablic i arginga:

$ cat tst.awk
{ lines[$0][FILENAME] }
END {
    for (line in lines) {
        if ( length(lines[line]) != ARGIND ) {
            printf "%s ==> ", line
            c = 0
            for (file in lines[line]) {
                printf "%s%s", (c++ ? ", " : ""), file
            }
            print ""
        }
    }
}

$ awk -f tst.awk file1 file2 file3
ghi 789 ==> file2, file3
<abc> 123 ==> file1
0
Ed Morton 26 czerwiec 2017, 00:16