Jak sprawdzić, czy plik1 jest prefiksem pliku2?


13

Mam dwa pliki o rozmiarach 124665 i 124858 w bajtach i chcę sprawdzić, czy plik1 jest prefiksem pliku2, czy nie.

Odpowiedzi:


11

Załóżmy, że masz rozmiar file1zmiennej FILE1_SZi twoja headimplementacja obsługuje -copcję (niestandardową) :

if head -c "$FILE1_SZ" file2 | cmp -s - file1; then
    echo "file1 is a prefix of file2"
else
    echo "file1 is not a prefix of file2"
fi

@ StéphaneChazelas Czy możesz wyjaśnić, dlaczego cmpbyłoby lepiej niż difftutaj?
Joseph R.

7
Ponieważ cmpwykonuje proste porównanie bajt-bajt i zwraca, gdy tylko zauważy różnicę, a jednocześnie diffjest narzędziem tekstowym, które korzysta ze złożonego algorytmu, aby pokazać wszystkie różnice między dwoma plikami, na których ci nie zależy.
Stéphane Chazelas

12

Jeśli twój system ma cmppolecenie z GNU diffutils, to jedną z opcji jest

cmp -n 124665 file1 file2

porównać najwyżej pierwsze 124665 bajtów dwóch plików i zgłosić, jeśli się różnią - lub bardziej ogólnie

cmp -n "$(wc -c < file1)" file1 file2

@StephaneChazelas Zgaduję tutaj po raz drugi, ale czy lepiej byłoby zasugerować $(stat -c %s file1)rozmiar w bajtach? Czy wcfaktycznie otwiera i przetwarza cały plik, aby uzyskać liczbę bajtów?
steeldriver

2
nie, większość wcimplementacji zoptymalizuje tę sprawę i zrobi fstat()(lub / i a lseek(SEEK_END)), więc będzie tak wydajna, jak to możliwe. Z drugiej strony stat -cjest to specyficzne dla GNU.
Stéphane Chazelas

1
Chociaż jeśli będziesz wymagał specyficznych dla GNU cmp, możesz rozsądnie założyć, że są specyficzne dla GNU stat.
Barmar

3

GNU cmpmoże rozwiązać problem w łatwiejszy sposób:

cmp file1 file2

Istnieją cztery możliwe wyniki (z wyjątkiem jakiegoś błędu).

  • Brak danych wyjściowych: pliki są identyczne.

  • cmp: EOF on file1: plik1 jest prefiksem pliku2.

  • cmp: EOF on file2: plik2 jest prefiksem pliku1.

  • file1 file2 differ: byte NNN, line MMM: Żaden nie jest przedrostkiem drugiego.

Niestety jest to trochę niewygodne w użyciu w skrypcie, ponieważ te przypadki nie wydają się być rozróżniane w kodzie wyjścia. Ponadto EOF on file1wiadomości trafiają do stderr, podczas gdy file1 file2 differwiadomość trafia do stdout.

Zakładam, że inne wersje cmprobią coś podobnego, ale nie sprawdziłem.


1
cmpnie jest poleceniem opartym tylko na GNU, ani się tam nie wywodzi, był już w pierwszej wersji Uniksa na początku lat 70. Ta -nopcja jest jednak specyficzna dla GNU.
Stéphane Chazelas

Mógłbyś zrobićcmp file1 file2 2>&1 | grep EOF on file1
David Z

@ StéphaneChazelas: To prawda. Nie chciałem sugerować, że cmpbyło to unikalne dla GNU, tylko że GNU cmpbyła jedyną wersją, której próbowałem. Dodałem zdanie w celu wyjaśnienia.
Nate Eldredge

@DavidZ: Tak, możesz, ale robi się trochę mniej solidny. Wyobraź sobie, że próbujesz to zrobić za pomocą dwóch plików dostarczonych przez użytkownika, a jeden z nich ma nazwę, file1a drugi nazwę file12. (Lub jeszcze gorzej, co jeśli drugi plik zostanie nazwany EOF on file1?) Solidne rozwiązanie tego problemu cmpjest prawdopodobnie znacznie większym problemem niż napisanie oczywistego 5-liniowego programu w C ...
Nate Eldredge

Mogą jednak istnieć konteksty, w których program C nie jest praktyczny. I nie jest to takie trudne, aby było dość solidne, ponieważ moc wyjściowa cmpjest tak ściśle ograniczona. Użycie -xopcji włącz, grepaby dopasować całą linię, zajmie się wszystkimi przypadkami oprócz najbardziej egzotycznych (np. Znaki nowej linii w nazwie pliku).
David Z
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.