Diff jefe de archivos

11

Tengo dos archivos Sospecho que un archivo es un subconjunto del otro. ¿Hay alguna manera de diferenciar los archivos para identificar (de manera sucinta) dónde en el primer archivo cabe el segundo archivo?

Ricardo
fuente
¿Quiere decir que las líneas de un archivo son una subsecuencia del otro, o en realidad una subcadena contigua?
Kaz
Una subcadena contigua, @Kaz.
Richard

Respuestas:

14

diff -e bigger smaller hará el truco, pero requiere cierta interpretación, ya que el resultado es un "script ed válido".

Hice dos archivos, "más grande" y "más pequeño", donde el contenido de "más pequeño" es idéntico a las líneas 5 a 9 de "más grande" haciendo 'diff -e más grande más pequeño "me consiguió:

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

Lo que significa "eliminar las líneas 10 a 15 de 'más grande', y luego eliminar las líneas 1 a 4, para obtener 'más pequeño'". Eso significa que "más pequeño" son las líneas 5 a 9 de "más grande".

Invertir los nombres de los archivos me dio algo más complicado. Si "más pequeño" realmente constituye un subconjunto de "más grande", solo los comandos 'd' (para eliminar) aparecerán en la salida.

Bruce Ediger
fuente
5

Puedes hacer esto visualmente con meld . Desafortunadamente, es una herramienta GUI, pero si solo quieres hacer esto una vez, y en un archivo relativamente pequeño, debería estar bien:

La siguiente imagen es la salida de meld a b:

ingrese la descripción de la imagen aquí

terdon
fuente
1
Meld es bueno, pero no funciona tan bien con archivos de más de 100 MB.
Richard
@ Richard no, no lo hace y preferiría una herramienta de línea de comandos de todos modos, solo pensé en mencionarlo.
terdon
Se parece mucho vimdiff, que está disponible en la terminal.
Patrick
2

Si los archivos son lo suficientemente pequeños, puede arrastrarlos a Perl y hacer que su motor de expresiones regulares haga el truco:

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

El -0777conmutador le indica a Perl que establezca su separador de registro de entrada $/en el valor indefinido para sorber los archivos por completo.

Joseph R.
fuente
1
¿Qué 777hacer? Supongo que estás pasando NULL, $/pero ¿por qué? Además, dado que estos son interruptores esotéricos, una explicación sería buena para las personas que no son perl.
terdon
1
@terdon De hecho, lo estoy haciendo para sorber los archivos completos. Explicación agregada.
Joseph R.
¿Pero por qué es eso necesario? $a=<$fh>debería sorber de todos modos, ¿verdad?
terdon
1
@terdon No que yo sepa, no. De manera predeterminada, $/se establece en de \nmodo que $a=<$fh>solo se $fhabriría una línea del archivo . A menos que, por supuesto perl, el comportamiento de la línea de comandos tenga valores predeterminados diferentes que desconozco.
Joseph R.
Argh, sí, mi mal, casi nunca sorbo archivos o uso el while $foo=<FILE>idioma, así que no estaba seguro y realicé una prueba (incorrecta) que parecía funcionar. No importa :).
terdon
1

Si los archivos son archivos de texto y smaller, al biggercomenzar al principio de una línea, no es demasiado difícil de implementar 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
Stéphane Chazelas
fuente
1

Su pregunta es "Diff head of files". Si realmente quiere decir que un archivo es la cabeza del otro, entonces un simple cmple dirá que:

cmp big_file small_file
cmp: EOF on small_file

Eso le dice que no se detectó una diferencia entre los dos archivos hasta que se alcanzó el final del archivo mientras se leía small_file.

Sin embargo, si quiere decir que todo el texto del archivo pequeño puede aparecer en cualquier parte del interior big_file, suponiendo que pueda guardar ambos archivos en la memoria, puede usar

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

Esto imprimirá el desplazamiento dentro de big_filedonde se encuentran los contenidos de small_file(por ejemplo, 0 si small_filecoincide al principio de big_file). Si small_fileno coincide dentro big_file, entonces no se imprimirá nada. Si hay un error, el estado de salida será distinto de cero.

jrw32982 es compatible con Monica
fuente