Comment vérifier si file1 est un préfixe de file2?

13

J'ai deux fichiers de tailles 124665 et 124858 en octets et je veux vérifier si file1 est un préfixe de file2 ou non.

tvorog
la source

Réponses:

11

Supposons que vous ayez la taille de file1dans la variable FILE1_SZet que votre headimplémentation prenne en charge l' -coption (non standard) :

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
Joseph R.
la source
@ StéphaneChazelas Pouvez-vous expliquer pourquoi ce cmpserait mieux diffqu'ici?
Joseph R.
7
Parce que cmpfait une simple comparaison d'octet à octet, et retourne dès qu'il trouve une différence, alors diffqu'un utilitaire de texte va utiliser un algorithme complexe pour vous montrer toutes les différences entre les deux fichiers qui ne vous intéressent pas.
Stéphane Chazelas
12

Si votre système a la cmpcommande de GNU diffutils, alors une option est

cmp -n 124665 file1 file2

comparer au maximum les 124665 premiers octets des deux fichiers et signaler s'ils diffèrent - ou, plus généralement

cmp -n "$(wc -c < file1)" file1 file2
tournevis
la source
@StephaneChazelas Je suis en train de me deviner ici, mais aurait-il été préférable de suggérer $(stat -c %s file1)la taille en octets? Est-ce que wcréellement ouvrir et traiter le fichier entier pour obtenir le nombre d'octets?
steeldriver
2
non, la plupart des wcimplémentations optimiseront ce cas et feront un fstat()(ou / et un lseek(SEEK_END)) donc seront aussi efficaces que possible. D'un autre côté, c'est stat -cspécifique à GNU.
Stéphane Chazelas
1
Bien que si vous avez besoin de la spécificité GNU cmp, vous pouvez raisonnablement supposer qu'elle est spécifique à GNU stat.
Barmar
3

GNU cmppeut résoudre le problème d'une manière plus simple:

cmp file1 file2

Il y a quatre sorties possibles (sauf erreur).

  • Pas de sortie: les fichiers sont identiques.

  • cmp: EOF on file1: file1 est un préfixe de file2.

  • cmp: EOF on file2: file2 est un préfixe de file1.

  • file1 file2 differ: byte NNN, line MMM: Aucun n'est un préfixe de l'autre.

Malheureusement, c'est un peu gênant à utiliser dans un script, car ces cas ne semblent pas être distingués dans le code de sortie. De plus, les EOF on file1messages vont à stderr, tandis que le file1 file2 differmessage va à stdout.

Je suppose que les autres versions de cmpfont quelque chose de similaire, mais je n'ai pas vérifié.

Nate Eldredge
la source
1
cmpn'est pas une commande GNU uniquement et n'y est pas originaire, elle était déjà dans la première version d'Unix au début des années 70. L' -noption est cependant spécifique à GNU.
Stéphane Chazelas
Vous pourriez le fairecmp file1 file2 2>&1 | grep EOF on file1
David Z
@ StéphaneChazelas: C'est vrai. Je ne voulais pas laisser entendre que cmpc'était unique à GNU, juste que GNU cmpétait la seule version que j'ai essayée. J'ai ajouté une phrase pour clarifier.
Nate Eldredge
@DavidZ: Oui, vous pourriez, mais cela devient un peu moins robuste. Imaginez que vous essayez de le faire avec deux fichiers fournis par l'utilisateur, et l'un d'eux est nommé file1et l'autre est nommé file12. (Ou pire encore, que se passe-t-il si le deuxième fichier est nommé EOF on file1?) La résolution de cette utilisation robuste cmpest probablement beaucoup plus difficile que d'écrire le programme évident de 5 lignes en C ...
Nate Eldredge
Il peut cependant y avoir des contextes où un programme C n'est pas pratique. Et ce n'est pas si difficile de le rendre assez robuste, car la sortie de cmpest si étroitement contrainte. L'utilisation de l' -xoption on greppour faire correspondre la ligne entière prendra en charge tous les cas, sauf les plus exotiques (par exemple, les nouvelles lignes dans le nom de fichier).
David Z