J'ai deux fichiers. Un fichier, je suppose, est un sous-ensemble de l'autre. Existe-t-il un moyen de différencier les fichiers pour identifier (de manière succincte) où dans le premier fichier le deuxième fichier tient?
J'ai deux fichiers. Un fichier, je suppose, est un sous-ensemble de l'autre. Existe-t-il un moyen de différencier les fichiers pour identifier (de manière succincte) où dans le premier fichier le deuxième fichier tient?
Réponses:
diff -e bigger smaller
fera l'affaire, mais nécessite une certaine interprétation, car la sortie est un "script ed valide".
J'ai fait deux fichiers, "plus gros" et "plus petit", où le contenu de "plus petit" est identique aux lignes 5 à 9 de "plus grand" faisant "diff -e plus grand plus petit" m'a obtenu:
% diff -e bigger smaller
10,15d
1,4d
Ce qui signifie "supprimer les lignes 10 à 15 de" plus grandes ", puis supprimer les lignes 1 à 4, pour devenir" plus petites "". Cela signifie que "plus petit" correspond aux lignes 5 à 9 de "plus grand".
Inverser les noms de fichiers m'a rendu quelque chose de plus compliqué. Si «plus petit» constitue vraiment un sous-ensemble de «plus grand», seules les commandes «d» (pour suppression) apparaîtront dans la sortie.
Vous pouvez le faire visuellement avec meld . Malheureusement, c'est un outil GUI mais si vous ne voulez le faire qu'une seule fois, et sur un fichier relativement petit, ça devrait aller:
L'image ci-dessous est la sortie de meld a b
:
vimdiff
, qui est disponible dans le terminal.
Si les fichiers sont suffisamment petits, vous pouvez les extraire tous les deux dans Perl et demander à son moteur regex de faire l'affaire:
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";
'
Le -0777
commutateur demande à Perl de définir son séparateur d'enregistrements d'entrée $/
sur la valeur indéfinie afin de slurper complètement les fichiers.
777
-il? Je suppose que vous passez NULL $/
mais pourquoi? De plus, comme ce sont des commutateurs un peu ésotériques, une explication serait bien pour les non-perl.
$a=<$fh>
devrait slurp de toute façon à droite?
$/
est défini sur \n
pour que la $a=<$fh>
lecture d'une seule ligne du fichier $fh
soit ouverte. À moins bien sûr que perl
le comportement de la ligne de commande ait des valeurs par défaut différentes que je ne connais pas?
while $foo=<FILE>
idiome, donc je n'étais pas sûr et j'ai exécuté un (mauvais) test qui semblait fonctionner. Ça ne fait rien :).
Si les fichiers sont des fichiers texte et smaller
, dans bigger
commence au début d'une ligne, ce n'est pas trop difficile à implémenter avec 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
Votre question est "Tête de fichier diff". Si vous voulez vraiment dire qu'un fichier est la tête de l'autre, alors un simple cmp
vous dira que:
cmp big_file small_file
cmp: EOF on small_file
Cela vous indique qu'une différence entre les deux fichiers n'a pas été détectée avant la fin du fichier lors de la lecture small_file
.
Si toutefois vous voulez dire que l'intégralité du texte d'un petit fichier peut apparaître n'importe où à l'intérieur big_file
, alors en supposant que vous puissiez tenir les deux fichiers en mémoire, vous pouvez utiliser
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;
'
Cela imprimera le décalage à l'intérieur big_file
du contenu de small_file
(par exemple 0 si small_file
correspond au début de big_file
). Si small_file
ne correspond pas à l'intérieur big_file
, rien ne sera imprimé. S'il y a une erreur, l'état de sortie sera différent de zéro.