Ich habe zwei Dateien. Ich vermute, eine Datei ist eine Teilmenge der anderen. Gibt es eine Möglichkeit, die Dateien zu unterscheiden, um (auf prägnante Weise) zu identifizieren, wo in die erste Datei die zweite Datei passt?
Ich habe zwei Dateien. Ich vermute, eine Datei ist eine Teilmenge der anderen. Gibt es eine Möglichkeit, die Dateien zu unterscheiden, um (auf prägnante Weise) zu identifizieren, wo in die erste Datei die zweite Datei passt?
Antworten:
diff -e bigger smaller
wird den Trick machen, erfordert aber einige Interpretation, da die Ausgabe ein "gültiges ed-Skript" ist.
Ich habe zwei Dateien erstellt, "größer" und "kleiner", wobei der Inhalt von "kleiner" mit den Zeilen 5 bis 9 von "größer" identisch ist, wobei "diff -e größer kleiner" mich dazu gebracht hat:
% diff -e bigger smaller
10,15d
1,4d
Dies bedeutet "Löschen Sie die Zeilen 10 bis 15 von" größer "und dann die Zeilen 1 bis 4, um" kleiner "zu werden". Das heißt, "kleiner" sind die Zeilen 5 bis 9 von "größer".
Das Umkehren der Dateinamen hat mich etwas komplizierter gemacht. Wenn "kleiner" wirklich eine Teilmenge von "größer" darstellt, werden in der Ausgabe nur "d" -Befehle (zum Löschen) angezeigt.
Sie können dies visuell mit meld tun . Leider ist es ein GUI-Tool, aber wenn Sie dies nur einmal und in einer relativ kleinen Datei tun möchten, sollte es in Ordnung sein:
Das Bild unten ist die Ausgabe von meld a b
:
vimdiff
, was im Terminal verfügbar ist.
Wenn die Dateien klein genug sind, können Sie beide in Perl schlürfen und die Regex-Engine den Trick ausführen lassen:
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";
'
Der -0777
Switch weist Perl an, das Trennzeichen $/
für Eingabedatensätze auf den undefinierten Wert zu setzen, um Dateien vollständig zu verschlingen.
777
das Ich nehme an, Sie übergeben NULL, $/
aber warum? Auch da dies irgendwie esoterische Schalter sind, wäre eine Erklärung für die Nicht-Perl-Leute nett.
$a=<$fh>
sollte sowieso schlürfen oder?
$/
ist so eingestellt, \n
dass $a=<$fh>
nur eine Zeile der Datei gelesen wird, für die $fh
geöffnet wurde. Es sei denn natürlich perl
, das Befehlszeilenverhalten hat andere Standardeinstellungen, die mir nicht bekannt sind.
while $foo=<FILE>
Redewendung, also war ich mir nicht sicher und führte einen (falschen) Test durch, der zu funktionieren schien. Keine Ursache :).
Wenn es sich bei den Dateien um Textdateien handelt und smaller
innerhalb von bigger
am Anfang einer Zeile beginnt, ist die Implementierung nicht allzu schwierig mit 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
Ihre Frage lautet "Diff head of files". Wenn Sie wirklich meinen, dass eine Datei der Kopf der anderen ist, dann cmp
sagt Ihnen eine einfache Datei Folgendes:
cmp big_file small_file
cmp: EOF on small_file
Dies zeigt Ihnen, dass ein Unterschied zwischen den beiden Dateien erst erkannt wurde, als beim Lesen das Dateiende erreicht wurde small_file
.
Wenn Sie jedoch meinen, dass der gesamte Text einer kleinen Datei irgendwo im Inneren vorkommen kann big_file
, können Sie verwenden, vorausgesetzt, Sie können beide Dateien in den Speicher einpassen
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;
'
Dadurch wird der Versatz gedruckt, in big_file
dem sich der Inhalt von small_file
befindet (z. B. 0, wenn er small_file
zu Beginn übereinstimmt big_file
). Wenn small_file
es innen nicht übereinstimmt big_file
, wird nichts gedruckt. Wenn ein Fehler auftritt, ist der Exit-Status ungleich Null.