Como associar o número da linha de um arquivo ao arquivo de resultado de saída diff lado a lado?

Como associar o número da linha de um arquivo ao arquivo de resultado de saída diff lado a lado?

Meu cenário é esse:

Primeiro gere diffdois arquivos lado a lado usando:

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

Saída de DiffResult.txt:

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

Agora vamos dizer a linha

This is line A

e

This is line B

estão na linha 5 de file1.txte file2.txtrespectivamente. Então eu deveria ser capaz de associar o número de linha apropriado a ele da seguinte maneira:

Saída desejada 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

A razão pela qual estou optando por essa abordagem é porque se eu gerar números de linha antes diff, mesmo para uma pequena alteração no espaço em branco, isso diffmostraria uma diferença por causa dos números de linha associados às linhas.

Alguém com ideias brilhantes? Acho que essa é a pergunta mais difícil que já foi feita no StackExchange, acredito:D

Responder1

O problema pode ser resolvido filtrando a saída de diff. Este exemplo funciona para mim (embora o posicionamento e o tamanho da medianiz entre os lados esquerdo/direito da saída diff provavelmente sejam um detalhe que difere entre as implementações):

#!/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;
    }
}
'

Você não pode adicionar números de linhaantes diff, porque se houver inserções ou exclusões, os números das linhas começando nesse ponto não corresponderão, tornando as diferenças inúteis. Meu script calcula os números de linha para os lados esquerdo/direito da diferença no script awk:

  • Primeiro ele decide a largura da diferença, com base na largura do terminal.
  • Existe (no GNU diff 3.2 que testei) umcalha(espaço não utilizado) no meio das diferenças lado a lado. Começando com um terminal de 80 colunas, determinei uma maneira de calcular a posição da calha.
  • Após inicializar, o script extrai de cada linha (in awk, isto é $0) as strings esquerda ( textL) e direita ( textR), e testa se elas estão vazias (o que aconteceria se houvesse um insert/delete).
  • Se as linhas esquerda/direita forem diferentes, o script reconstrói a diffsaída, mas adicionando os números das linhas.

Dado isso à esquerda

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

yyy

e isso à direita

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

(10 linhas à esquerda, 9 à direita), este script produz

    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                                     <        

informação relacionada