¿Cómo se difieren los files que ignoran los comentarios (líneas que comienzan con #)?

Tengo dos files de configuration, el original del administrador de packages y uno personalizado modificado por mí mismo. He agregado algunos comentarios para describir el comportamiento.

¿Cómo puedo ejecutar diff en los files de configuration, omitiendo los comentarios? Una línea comentada se define por:

  • espacios en blanco iniciales opcionales (tabs y espacios)
  • signo hash ( # )
  • cualquier otro personaje

La expresión regular (más simple) salteando el primer requisito sería #.* . Intenté la opción --ignore-matching-lines=RE ( -I RE ) de GNU diff 3.0, pero no pude lograr que funcionara con esa RE. También probé .*#.* .*\#.* Sin suerte. Literalmente, poner la línea ( Port 631 ) como RE no coincide con nada, tampoco ayuda a poner el RE entre barras diagonales.

Como se sugiere en el sabor de la herramienta "diff", la expresión regular parece carecer? , grep -G :

 grep -G '#.*' file 

Esto parece coincidir con los comentarios, pero no funciona para diff -I '#.*' file1 file2 .

Entonces, ¿cómo debe usarse esta opción? ¿Cómo puedo hacer que diff salte ciertas líneas (en mi caso, comentarios)? No sugiera que se grep el file y que se comparen los files temporales.

Según Gilles, la opción -I solo ignora una línea si nada más dentro de ese set coincide, excepto por la coincidencia de -I . No lo entendí del todo hasta que lo probé.

La testing

Tres files están involucrados en mi testing: Archivo test1:

  text 

Archivo test2:

  text #comment 

Archivo test3:

  changed text #comment 

Los commands:

 $ # comparing files with comment-only changes $ diff -u -I '#.*' test{1,2} $ # comparing files with both comment and regular changes $ diff -u -I '#.*' test{2,3} --- test2 2011-07-20 16:38:59.717701430 +0200 +++ test3 2011-07-20 16:39:10.187701435 +0200 @@ -1,2 +1,2 @@ -text +changed text #comment 

La forma alternativa

Dado que hasta el momento no hay respuesta que explique cómo utilizar la opción -I correctamente, proporcionaré una alternativa que funciona en bash shells:

 diff -u -B <(grep -vE '^\s*(#|$)' test1) <(grep -vE '^\s*(#|$)' test2) 
  • diff -u – diff unificado
    • -B – ignora las líneas en blanco
  • <(command) – una function bash llamada sustitución de process que abre un descriptor de file para el command, esto elimina la necesidad de un file temporal
  • grep – command para líneas de printing (no) que coinciden con un patrón
    • -v – muestra líneas que no coinciden
    • E – use expresiones regulares extendidas
    • '^\s*(#|$)' – una expresión regular que coincide con los comentarios y líneas vacías
    • ^ – coincide con el comienzo de una línea
    • \s* – coincide con el espacio en blanco (tabs y espacios) si corresponde
    • (#|$) coincide con una marca de almohadilla o, como alternativa, al final de una línea

Tratar:

 diff -b -I '^#' -I '^ #' file1 file2 

Tenga en count que la expresión regular tiene que coincidir con la línea correspondiente en ambos files y coincide con cada línea modificada en el trozo para que funcione, de lo contrario, seguirá mostrando la diferencia.

Utilice comillas simples para proteger el patrón de la expansión del caparazón y para escaping de los caracteres reservados a la expresión regular (por ejemplo, corchetes).

Podemos leer en el manual de diffutils :

Sin embargo, solo ignoro la inserción o eliminación de líneas que contienen la expresión regular si cada línea cambiada en el trozo (cada inserción y cada eliminación) coincide con la expresión regular.

En otras palabras, para cada cambio no ignorable, diff imprime el set completo de cambios en su entorno, incluidos los ignorables. Puede especificar más de una expresión regular para que las líneas las ignoren al usar más de una opción -I . diff intenta hacer coincidir cada línea con cada expresión regular, comenzando con la última dada.

Este comportamiento también está bien explicado por armel aquí .

Por lo general, ignoro este desorder por:

  • Generando versiones no comentadas usando grep -v "^#" | cat -s grep -v "^#" | cat -s y difiriendo esos o …
  • Usando vim -d para mirar los files. El resaltado de syntax se encarga de hacer que las diferencias entre comentarios y no comentarios sean bastante obvias. El resaltado diferencial de la diferencia en línea para que pueda ver qué valores o partes de valores se han cambiado de un vistazo hace que este sea mi favorito.

Después de search en la web, una forma alternativa de Lekensteyn es la mejor que encontré.

Pero quiero utilizar la salida de Dif como parche … y hay un problema porque el número de línea es una nota guardada debido a "grep -v".

Así que me propongo mejorar esta línea de command:

 diff -u -B <(sed 's/^[[:blank:]]*#.*$/ /' file1) <(sed 's/^[[:blank:]]*#.*$/ /' file2) 

No es perfecto, pero el número de línea se guarda en el file de parche.

Sin embargo, si se agrega una nueva línea en lugar de la línea de comentario … el comentario se producirá un error FALLA al parchear, como podemos ver a continuación.

 File test1: text #comment other text File test2: text new line here #comment changed other text changed 

testing ahora nuestro command

 $ echo -e "#!/usr/bin/sed -f\ns/^[[:blank:]]*#.*$/ /" > outcom.sed $ echo "diff -u -B <(./outcom.sed \$1) <(./outcom.sed \$2)" > mydiff.sh $ chmod +x mydiff.sh outcom.sed $ ./mydiff.sh file1 file2 > file.dif $ cat file.dif --- /dev/fd/63 2014-08-23 10:05:08.000000000 +0200 +++ /dev/fd/62 2014-08-23 10:05:08.000000000 +0200 @@ -1,2 +1,3 @@ text +new line -other text +other text changed 

/ dev / fd / 62 y / dev / fd / 63 son files producidos por sustitución de processs. La línea entre "+ nueva línea" y "-otro text" es el carácter de espacio pnetworkingeterminado definido en nuestra expresión sed para replace los comentarios.

Y ahora, lo que viene cuando aplicamos este parche:

 $ patch -p0 file1 < file.dif patching file file1 Hunk #1 FAILED at 1. 1 out of 1 hunk FAILED -- saving rejects to file file1.rej 

La solución es no usar formatting unificado de diferencias sin -u

 $ echo "diff -B <(./outcom.sed \$1) <(./outcom.sed \$2)" > mydiff.sh $ ./mydiff.sh file1 file2 > file.dif $ cat file.dif 1a2 > new line 3c4 < other text --- > other text changed $ patch -p0 file1 < file.dif patching file file1 $ cat file1 text new line #comment other text changed 

ahora parche el file de trabajo del file (sin garantía de resultado en un process de diff muy complejo).

Esto es lo que uso para eliminar todas las líneas comentadas, incluso aquellas que comienzan con una pestaña o espacio, y las en blanco:

 egrep -v "^$|^[[:space:]]*#" /path/to/file 

o puedes hacer

 sed -e '/^#.*/d' -e 's/#.*//g' | cat -s