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?
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?
Odpowiedzi:
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).
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
:
vimdiff
, co jest dostępne w terminalu.
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";
'
-0777
Przełącznik przesyła zlecenie Perl aby ustawić jej separator rekordu wejściowego $/
do wartości nieokreślonej, tak aby pliki SLURP końca.
777
zrobić? 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.
$a=<$fh>
w każdym razie powinien to być slurp, prawda?
$/
jest ustawione na \n
tak, 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?
while $foo=<FILE>
idiomu, więc nie byłem pewien i przeprowadziłem (zły) test, który wydawał się działać. Nieważne :).
Jeśli pliki są plikami tekstowymi, a smaller
wewnątrz bigger
zaczyna 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
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 cmp
powie 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_file
którym znajduje się zawartość small_file
(np. 0, jeśli small_file
pasuje na początku big_file
). Jeśli small_file
nie pasuje do środka big_file
, nic nie zostanie wydrukowane. W przypadku błędu status wyjścia będzie różny od zera.