Zróżnicowana głowa plików

11

Mam dwa pliki. Podejrzewam, że jeden plik jest podzbiorem drugiego. Czy istnieje sposób na różnicowanie plików, aby zidentyfikować (w zwięzły sposób), gdzie w pierwszym pliku mieści się drugi plik?

Richard
źródło
Czy masz na myśli, że linie jednego pliku są podciągiem drugiego, a właściwie ciągłym ciągiem znaków?
Kaz
Ciągły podciąg, @Kaz.
Richard

Odpowiedzi:

14

diff -e bigger smaller zrobi lewę, ale wymaga pewnej interpretacji, ponieważ wynikiem jest „prawidłowy skrypt ed”.

Zrobiłem dwa pliki, „większy” i „mniejszy”, w których zawartość „mniejszego” jest identyczna z liniami od 5 do 9 „większego” robiącego „diff -e większy mniejszy” dostałem:

% diff -e bigger smaller
10,15d
1,4d

Co oznacza „usuń wiersze od 10 do 15 z„ większych ”, a następnie usuń wiersze od 1 do 4, aby uzyskać„ mniejsze ”. Oznacza to, że „mniejsze” to wiersze od 5 do 9 „większego”.

Odwracanie nazw plików sprawiło mi coś bardziej skomplikowanego. Jeśli „mniejsze” naprawdę stanowi podzbiór „większych”, na wyjściu pojawią się tylko polecenia „d” (do usunięcia).

Bruce Ediger
źródło
5

Możesz to zrobić wizualnie za pomocą meld . Niestety jest to narzędzie GUI, ale jeśli chcesz to zrobić tylko raz i na stosunkowo małym pliku, powinno być dobrze:

Poniższy obraz przedstawia dane wyjściowe meld a b:

wprowadź opis zdjęcia tutaj

terdon
źródło
1
Meld jest fajny, ale nie gra tak dobrze z plikami ponad 100 MB.
Richard
@Richard nie, nie robi tego i tak wolałbym narzędzie wiersza poleceń, pomyślałem, że o tym wspomnę.
terdon
Wygląda podobnie do tego vimdiff, co jest dostępne w terminalu.
Patrick
2

Jeśli pliki są wystarczająco małe, możesz przelać je oba do Perla i poprosić jego silnik wyrażenia regularnego:

perl -0777e '
        open "$FILE1","<","file_1";
        open "$FILE2","<","file_2";
        $file_1 = <$FILE1>;
        $file_2 = <$FILE2>;
        print "file_2 is", $file_1 =~ /\Q$file_2\E/ ? "" : "not";
        print " a subset of file_1\n";
'

-0777Przełącznik przesyła zlecenie Perl aby ustawić jej separator rekordu wejściowego $/do wartości nieokreślonej, tak aby pliki SLURP końca.

Joseph R.
źródło
1
Co ma 777zrobić? Rozumiem, że podajesz NULL, $/ale dlaczego? Ponieważ są to raczej ezoteryczne przełączniki, wyjaśnienie byłoby miłe dla osób nie będących w Perlu.
terdon
1
@terdon Naprawdę robię to, aby zatamować pliki w całości. Dodano wyjaśnienie.
Joseph R.
Ale dlaczego to konieczne? $a=<$fh>w każdym razie powinien to być slurp, prawda?
terdon
1
@terdon Nie wiem, nie. Domyślnie $/jest ustawione na \ntak, aby $a=<$fh>można było odczytać tylko jedną linię pliku $fh. Chyba perlże zachowanie wiersza polecenia ma oczywiście inne ustawienia domyślne, których nie jestem świadomy?
Joseph R.
Argh, tak, moje złe, prawie nigdy nie robię plików i nie używam tego while $foo=<FILE>idiomu, więc nie byłem pewien i przeprowadziłem (zły) test, który wydawał się działać. Nieważne :).
terdon
1

Jeśli pliki są plikami tekstowymi, a smallerwewnątrz biggerzaczyna się na początku wiersza, nie jest to zbyt trudne do wdrożenia za pomocą awk:

awk -v i=0 'NR==FNR{l[n++]=$0;next}
    {if ($0 == l[i]) {if (++i == n) {print FNR-n+1;exit}} else i=0}
    ' smaller bigger
Stéphane Chazelas
źródło
1

Twoje pytanie brzmi „Zróżnicowana głowa plików”. Jeśli naprawdę masz na myśli, że jeden plik jest głową drugiego, to prosty cmppowie ci, że:

cmp big_file small_file
cmp: EOF on small_file

Oznacza to, że różnica między tymi dwoma plikami nie została wykryta do momentu osiągnięcia końca pliku podczas odczytu small_file.

Jeśli jednak masz na myśli, że cały tekst małego pliku może wystąpić w dowolnym miejscu w środku big_file, zakładając, że możesz zmieścić oba pliki w pamięci, możesz użyć

perl -le '
   use autodie;
   undef $/;
   open SMALL, "<", "small_file";
   open BIG, "<", "big_file";
   $small = <SMALL>;
   $big = <BIG>;
   $pos = index $big, $small;
   print $pos if $pos >= 0;
'

Spowoduje to wydrukowanie przesunięcia w obrębie, w big_filektórym znajduje się zawartość small_file(np. 0, jeśli small_filepasuje na początku big_file). Jeśli small_filenie pasuje do środka big_file, nic nie zostanie wydrukowane. W przypadku błędu status wyjścia będzie różny od zera.

jrw32982 obsługuje Monikę
źródło