¿Cómo verificar si el archivo1 es un prefijo del archivo2?

13

Tengo dos archivos con tamaños 124665 y 124858 en bytes y quiero verificar si file1 es un prefijo de file2 o no.

tvorog
fuente

Respuestas:

11

Supongamos que tiene el tamaño de file1en la variable FILE1_SZy su headimplementación admite la -copción (no estándar) :

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.
fuente
@ StéphaneChazelas ¿Puede explicar por qué cmpsería mejor que diffaquí?
Joseph R.
77
Porque cmphace una comparación simple byte a byte y regresa tan pronto como encuentra una diferencia, mientras que diffes una utilidad de texto que usará un algoritmo complejo para mostrarle todas las diferencias entre los dos archivos que no le interesan.
Stéphane Chazelas
12

Si su sistema tiene el cmpcomando de GNU diffutils, entonces una opción es

cmp -n 124665 file1 file2

comparar a lo sumo los primeros 124665 bytes de los dos archivos e informar si difieren, o más generalmente

cmp -n "$(wc -c < file1)" file1 file2
conductor de acero
fuente
@StephaneChazelas Me estoy adivinando aquí, pero ¿habría sido mejor sugerir $(stat -c %s file1)el tamaño en bytes? ¿ wcRealmente abre y procesa todo el archivo para obtener el recuento de bytes?
steeldriver
2
no, la mayoría de las wcimplementaciones optimizarán ese caso y harán un fstat()(o / y a lseek(SEEK_END)) para que sea tan eficiente como sea posible. Por otro lado, eso stat -ces específico de GNU.
Stéphane Chazelas
1
Aunque si va a requerir el específico de GNU cmp, razonablemente puede suponer específico de GNU stat.
Barmar
3

GNU cmppuede resolver el problema de una manera más fácil:

cmp file1 file2

Hay cuatro salidas posibles (salvo algún tipo de error).

  • Sin salida: los archivos son idénticos.

  • cmp: EOF on file1: file1 es un prefijo de file2.

  • cmp: EOF on file2: file2 es un prefijo de file1.

  • file1 file2 differ: byte NNN, line MMM: Ninguno de los dos es un prefijo del otro.

Desafortunadamente, esto es un poco incómodo de usar en un script, ya que estos casos no parecen distinguirse en el código de salida. Además, los EOF on file1mensajes van a stderr, mientras que el file1 file2 differmensaje va a stdout.

Supongo que otras versiones de cmphacer algo similar, pero no lo he comprobado.

Nate Eldredge
fuente
1
cmpno es un comando solo de GNU ni se originó allí, ya estaba en la primera versión de Unix a principios de los años 70. Sin -nembargo, la opción es específica de GNU.
Stéphane Chazelas
Podrías hacerlocmp file1 file2 2>&1 | grep EOF on file1
David Z
@ StéphaneChazelas: Eso es cierto. No quise dar a entender que cmpera exclusivo de GNU, solo que GNU cmpera la única versión que probé. Agregué una oración para aclarar.
Nate Eldredge
@DavidZ: Sí, podría, pero se vuelve un poco menos robusto. Imagine que está intentando hacer esto con dos archivos proporcionados por el usuario, y uno de ellos se llamafile1 y el otro se nombra file12. (O peor aún, ¿qué pasa si se nombra el segundo archivo EOF on file1?) Resolver este uso de manera robusta cmpes probablemente mucho más problema que escribir el obvio programa de 5 líneas en C ...
Nate Eldredge
Sin embargo, puede haber contextos en los que un programa C no sea práctico. Y no es tan difícil hacerlo bastante robusto, porque la producción de cmpestá muy restringida. El uso de la -xopción greppara que coincida con la línea completa se encargará de todos los casos menos los más exóticos (por ejemplo, nuevas líneas en el nombre del archivo).
David Z