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

3

Meu cenário é o seguinte:

Primeiro, gere lado a lado diff de dois arquivos 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.txt e file2.txt respectivamente. Então eu deveria ser capaz de associar o número de linha apropriado a ele da seguinte forma:

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 para essa abordagem é porque, se eu gerar números de linha antes de diff , mesmo para uma pequena alteração de espaço em branco, o diff mostrará uma diferença devido aos números de linha associados às linhas .

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

    
por Ronit Mishra 24.09.2016 / 10:39

1 resposta

1

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 e direito da saída do diff sejam provavelmente 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;
    }
}
'

Não é possível adicionar números de linha antes diff , porque se houver inserções ou exclusões, os números de linha que começam nesse ponto não corresponderão, fazendo com que as diferenças não sejam úteis. Meu script calcula os números de linha para os lados esquerdo / direito da diferença no script awk:

  • Decide primeiro a largura para fazer o diff, com base na largura do terminal.
  • Existe (no GNU diff 3.2 que testei) um gutter (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 a inicialização, o script extrai de cada linha (em awk , isso é $0 ) as cadeias esquerda ( textL ) e direita ( textR ) e testa se estão vazias (o que aconteceria se houvesse uma inserção / exclusão).
  • Se as linhas esquerda / direita forem diferentes, o script reconstruirá a saída diff , mas adicionando os números de linha.

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), esse 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                                     <        
    
por 24.09.2016 / 17:10