Diff capo dei file


11

Ho due file. Un file, sospetto, è un sottoinsieme dell'altro. C'è un modo per diffondere i file per identificare (in modo sintetico) dove nel primo file si adatta il secondo file?



Vuoi dire che le linee di un file sono una sottosequenza dell'altro o in realtà una sottostringa contigua?
Kaz

Una sottostringa contigua, @Kaz.
Richard,

Risposte:


14

diff -e bigger smaller farà il trucco, ma richiede una certa interpretazione, poiché l'output è uno "script ed valido".

Ho creato due file, "più grande" e "più piccolo", in cui il contenuto di "più piccolo" è identico alle righe da 5 a 9 di "più grande" che fa "diff -e più grande" mi ha fatto:

% diff -e bigger smaller
10,15d
1,4d

Il che significa "elimina le righe da 10 a 15 di" più grande ", quindi elimina le righe da 1 a 4, per ottenere" più piccolo "". Ciò significa che "più piccolo" è le righe da 5 a 9 di "più grande".

Invertire i nomi dei file mi ha reso qualcosa di più complicato. Se "più piccolo" costituisce veramente un sottoinsieme di "più grande", nell'output verranno visualizzati solo i comandi "d" (per l'eliminazione).


5

Puoi farlo visivamente con la fusione . Sfortunatamente, è uno strumento GUI ma se vuoi farlo una volta sola, e su un file relativamente piccolo, dovrebbe andare bene:

L'immagine seguente è l'output di meld a b:

inserisci qui la descrizione dell'immagine


1
La fusione è buona, ma non funziona altrettanto bene con file da 100 MB +.
Richard,

@Richard no, e preferirei comunque uno strumento da riga di comando, ho pensato di menzionarlo.
terdon

Sembra molto simile vimdiff, disponibile nel terminale.
Patrick,

2

Se i file sono abbastanza piccoli, puoi inserirli entrambi in Perl e fare in modo che il suo motore regex faccia il trucco:

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";
'

Lo -0777switch indica a Perl di impostare il separatore del record di input $/sul valore indefinito in modo da snellire completamente i file.


1
Cosa fa 777? Suppongo che stai passando NULL come, $/ma perché? Anche dal momento che si tratta di interruttori esoterici, una spiegazione sarebbe utile per le persone non perl.
terdon

1
@terdon Lo sto davvero facendo per snellire i file interi. Spiegazione aggiunta.
Joseph R.,

Ma perché è necessario? $a=<$fh>dovrebbe bere comunque?
terdon

1
@terdon Non che io sappia, no. Per impostazione predefinita, $/è impostato in \nmodo da $a=<$fh>leggere solo una riga del file $fh. A meno che, naturalmente perl, il comportamento della riga di comando abbia impostazioni predefinite diverse di cui non sono a conoscenza?
Joseph R.,

Argh, sì, mio ​​male, non ho quasi mai bevuto file o usato il while $foo=<FILE>linguaggio quindi non ero sicuro e ho eseguito un test (sbagliato) che sembrava funzionare. Non importa :).
terdon

1

Se i file sono file di testo e smaller, all'interno biggercomincia all'inizio di una riga, non è troppo difficile da attuare con 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

1

La tua domanda è "Diff head of files". Se davvero intendi che un file è il capo dell'altro, allora un semplice cmpti dirà che:

cmp big_file small_file
cmp: EOF on small_file

Ciò indica che non è stata rilevata una differenza tra i due file fino a quando non è stata raggiunta la fine del file durante la lettura small_file.

Se tuttavia vuoi dire che l'intero testo di un piccolo file può essere presente ovunque all'interno big_file, quindi supponendo che tu possa adattare entrambi i file in memoria, puoi usare

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;
'

Questo stamperà l'offset all'interno del big_filepunto in cui small_filesi trova il contenuto di (ad es. 0 se small_filecorrisponde all'inizio di big_file). Se small_filenon corrisponde all'interno big_file, non verrà stampato nulla. Se si verifica un errore, lo stato di uscita sarà diverso da zero.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.