¿Cómo asociar el número de línea de un archivo al archivo de resultados de salida de diferencias en paralelo?

¿Cómo asociar el número de línea de un archivo al archivo de resultados de salida de diferencias en paralelo?

Mi escenario es que:

Primero genere dos archivos uno al lado diffdel otro usando:

diff -y --supress-common-lines file1.txt file2.txt > DiffResult.txt

Salida de DiffResult.txt:

   file1.txt             file2.txt
This is line A    |   This is line B
This is line C    |   This is line D

Ahora digamos la línea

This is line A

y

This is line B

están en la línea 5 de file1.txty file2.txtrespectivamente. Entonces debería poder asociarle el número de línea apropiado de la siguiente manera:

Salida deseada de DiffResult.txt:

      file1.txt                file2.txt
5   This is line A    |  5   This is line B
7   This is line C    |  7   This is line D

La razón por la que opto por este enfoque es porque si genero números de línea antes diff, incluso con un pequeño cambio de espacio en blanco, mostraría diffuna diferencia debido a los números de línea asociados con las líneas.

¿Alguien con ideas brillantes? Creo que esta es la pregunta más difícil que jamás se haya hecho en StackExchange, creo: D

Respuesta1

El problema se puede resolver filtrando la salida de diff. Este ejemplo funciona para mí (aunque es probable que la ubicación y el tamaño del margen entre los lados izquierdo y derecho de la salida de diferencias sean un detalle que difiera entre las implementaciones):

#!/bin/sh
# $Id: diff-two-column,v 1.2 2016/09/26 20:38:32 tom Exp $
# see http://unix.stackexchange.com/questions/312025/how-to-associate-line-number-from-a-file-to-the-side-by-side-diff-output-result

usage() {
    cat >&2 <<EOF
usage: $0 file1 file2
EOF
    exit 1
}

[ $# = 2 ] || usage
[ -f "$1" ] || usage
[ -f "$2" ] || usage

width=${COLUMNS:-80}
check=$(stty size|cut -d' ' -f2)
[ -n "$check" ] && width=$check

diff -W $width -y "$1" "$2" | \
expand | \
awk -v width=$width '
BEGIN {
    L=0;
    R=0;
    gutter = width / 2;
    half = gutter - 2;
}
{
    textL = substr($0, 1, half - 1);
    sub("[ ]+$", "", textL);  # trim trailing blanks

    # The script relies on correctly extracting textM, the gutter:
    # if lines differ,    textM is " ! "
    # if line inserted,   textM is " > "
    # if line deleted,    textM is " < "
    # if lines unchanged, textM is "   "
    textM = substr($0, gutter - 2, 3);

    textR = ( length($0) > gutter ) ? substr($0, gutter+1, half) : "";

    if ( textM != " > " ) {
         L++;
    }
    if ( textM != " < " ) {
         R++;
    }

    if ( textL != textR ) {
        # printf "SHOW %s\n", $0;
        # printf "gap \"%s\"\n", textM;
        # printf "<<< \"%s\"\n", textL;
        # printf ">>> \"%s\"\n", textR;
        if ( textL == "" ) {
            printf "%5s %-*s %-3s %5d %s\n",
                " ", half, textL,
                textM,
                R, textR;
        } else if ( textR == "" ) {
            printf "%5d %-*s %-3s %5s %s\n",
                L, half, textL,
                textM,
                " ", textR;
        } else {
            printf "%5d %-*s %-3s %5d %s\n",
                L, half, textL,
                textM,
                R, textR;
        }
    } else {
        # printf "SKIP %s\n", $0;
    }
}
'

No puedes agregar números de líneaantes diff, porque si hay inserciones o eliminaciones, los números de línea que comienzan en ese punto no coincidirán, haciendo que las diferencias no sean útiles. Mi script calcula los números de línea para los lados izquierdo/derecho de la diferencia en el script awk:

  • Primero decide qué tan ancho hacer la diferencia, según el ancho del terminal.
  • Hay (en GNU diff 3.2 que probé) uncanal(espacio no utilizado) en medio de las diferencias de lado a lado. Comenzando con una terminal de 80 columnas, determiné una forma de calcular la posición del canal.
  • Después de la inicialización, el script extrae de cada línea (en awk, esto es $0) las cadenas izquierda ( textL) y derecha ( textR), y prueba si están vacías (lo que sucedería si hubiera una inserción/eliminación).
  • Si las líneas izquierda/derecha son diferentes, el script reconstruye la diffsalida, pero agregando los números de línea.

Dado esto a la izquierda

1
2
3
4
This is line A
6
This is line C
123456789.123456789.123456789.123456789.123456789.

yyy

y esto a la derecha

1
2
3
4
This is line B
6
This is line D
abcdefghi.abcdefghi.abcdefghi.abcdefghi.abcdefghi.
xxx

(10 líneas a la izquierda, 9 a la derecha), este script produce

    5 This is line A                          |      5 This is line B
    7 This is line C                          |      7 This is line D
    8 123456789.123456789.123456789.1234567   |      8 abcdefghi.abcdefghi.abcdefghi.abcdefg
                                              |      9 xxx
   10 yyy                                     <        

información relacionada