it-swarm.it

diff all'interno di una linea

Ho alcune discariche sql che sto esaminando le differenze tra. diff può ovviamente mostrarmi la differenza tra due righe, ma mi sto facendo impazzire cercando di trovare quali valori nella lunga lista di valori separati da virgola sono in realtà quelli che fanno sì che le linee siano diverse.

Quale strumento posso usare per evidenziare le differenze esatte tra i caratteri tra due righe in determinati file?

120
user394

C'è wdiff , il diff di Word per quello.

Sul desktop, fusione può evidenziare le differenze all'interno di una linea per te.

96
alex

Solo un altro metodo che utilizza git-diff:

git diff -U0 --Word-diff --no-index -- foo bar | grep -v ^@@

grep -v se non interessato alle posizioni dei diff.

31
Deepak

Ho usato vimdiff per questo.

Ecco uno screenshot (non mio) che mostra differenze minori di uno o due caratteri che si distinguono abbastanza bene. A anche tutorial veloce .

24
Mark McKinstry

Ecco un metodo "..hair del cane che ti ha morso" ...
diff ti ha portato a questo punto; usalo per portarti oltre ...

Ecco l'output dell'utilizzo delle coppie di righe di esempio ... indica una TAB

Paris in the     spring 
Paris in the the spring 
             vvvv      ^

A ca t on a hot tin roof.
a cant on a hot  in roof 
║   v           ^       ^

the quikc brown box jupps ober the laze dogs 
The☻qui ckbrown fox jumps over the lazy dogs 
║  ║   ^ ║      ║     ║    ║          ║     ^

Ecco lo script .. Devi solo scovare le coppie di linee in qualche modo .. (Ho usato diff solo una volta (due volte?) Prima di oggi, quindi non conosco le sue molte opzioni e selezionando le opzioni per questo la sceneggiatura mi è bastata, per un giorno :) .. Penso che debba essere abbastanza semplice, ma sono in pausa per una pausa caffè ....

#
# Name: hair-of-the-diff
# Note: This script hasn't been extensively tested, so beware the alpha bug :) 
#   
# Brief: Uses 'diff' to identify the differences between two lines of text
#        $1 is a filename of a file which contains line pairs to be processed
#
#        If $1 is null "", then the sample pairs are processed (see below: Paris in the spring 
#          
# ║ = changed character
# ^ = exists if first line, but not in second 
# v = exists if second line, but not in first

bname="$(basename "$0")"
workd="/tmp/$USER/$bname"; [[ ! -d "$workd" ]] && mkdir -p "$workd"

# Use $1 as the input file-name, else use this Test-data
# Note: this test loop expands \t \n etc ...(my editor auto converts \t to spaces) 
if [[ "$1" == '' ]] ;then
  ifile="$workd/ifile"
{ while IFS= read -r line ;do echo -e "$line" ;done <<EOF
Paris in the spring 
Paris in the the spring
A cat on a hot tin roof.
a cant on a hot in roof
the quikc brown box jupps ober the laze dogs 
The\tquickbrown fox jumps over the lazy dogs
EOF
} >"$ifile"
else
  ifile="$1"
fi
#
[[ -f "$ifile" ]] || { echo "ERROR: Input file NOT found:" ;echo "$ifile" ;exit 1 ; }
#  
# Check for balanced pairs of lines
ilct=$(<"$ifile" wc -l)
((ilct%2==0)) || { echo "ERROR: Uneven number of lines ($ilct) in the input." ;exit 2 ; }
#
ifs="$IFS" ;IFS=$'\n' ;set -f
ix=0 ;left=0 ;right=1
while IFS= read -r line ;do
  pair[ix]="$line" ;((ix++))
  if ((ix%2==0)) ;then
    # Change \x20 to \x02 to simplify parsing diff's output,
    #+   then change \x02 back to \x20 for the final output. 
    # Change \x09 to \x01 to simplify parsing diff's output, 
    #+   then change \x01 into ☻ U+263B (BLACK SMILING FACE) 
    #+   to the keep the final display columns in line. 
    #+   '☻' is hopefully unique and obvious enough (otherwise change it) 
    diff --text -yt -W 19  \
         <(echo "${pair[0]}" |sed -e "s/\x09/\x01/g" -e "s/\x20/\x02/g" -e "s/\(.\)/\1\n/g") \
         <(echo "${pair[1]}" |sed -e "s/\x09/\x01/g" -e "s/\x20/\x02/g" -e "s/\(.\)/\1\n/g") \
     |sed -e "s/\x01/☻/g" -e "s/\x02/ /g" \
     |sed -e "s/^\(.\) *\x3C$/\1 \x3C  /g" \
     |sed -n "s/\(.\) *\(.\) \(.\)$/\1\2\3/p" \
     >"$workd/out"
     # (gedit "$workd/out" &)
     <"$workd/out" sed -e "s/^\(.\)..$/\1/" |tr -d '\n' ;echo
     <"$workd/out" sed -e "s/^..\(.\)$/\1/" |tr -d '\n' ;echo
     <"$workd/out" sed -e "s/^.\(.\).$/\1/" -e "s/|/║/" -e "s/</^/" -e "s/>/v/" |tr -d '\n' ;echo
    echo
    ((ix=0))
  fi
done <"$ifile"
IFS="$ifs" ;set +f
exit
#
6
Peter.O

wdiff è in realtà un metodo molto vecchio per confrontare i file parola per parola. Ha funzionato riformattando i file, quindi usando diff per trovare le differenze e passarlo di nuovo indietro. Io stesso ho suggerito di aggiungere un contesto, in modo che, anziché confrontarlo parola per parola, lo faccia con ogni parola circondata da altre parole "contestuali". Ciò consente al diff di sincronizzarsi molto meglio sui passaggi comuni nei file, specialmente quando i file sono per lo più diversi con solo pochi blocchi di parole comuni. Ad esempio, quando si confronta il testo per plagio o per il riutilizzo.

dwdiff è stato successivamente creato da wdiff. Ma dwdiff usa quella funzione di riformattazione del testo con buoni risultati in dwfilter. Questo è un grande sviluppo: significa che è possibile riformattare un testo in modo che corrisponda a un altro e quindi confrontarlo utilizzando qualsiasi visualizzatore grafico diff riga per riga. Ad esempio, usandolo con diff "diffuso" grafico ....

dwfilter file1 file2 diffuse -w

Questo riformatta file1 nel formato di file2 e lo fornisce a diffuse per un confronto visivo. file2 non è modificato, quindi puoi modificare e unire le differenze di Word direttamente in diffuse. Se vuoi modificare file1, Puoi aggiungere -r per invertire il file che viene riformattato. Provalo e scoprirai che è estremamente potente!

La mia preferenza per il diff grafico (mostrato sopra) è diffuse poiché sembra molto più pulito e utile. Inoltre è un standalone python, il che significa che è facile da installare e distribuire ad altri sistemi UNIX.

Altre differenze grafiche sembrano avere molte dipendenze, ma possono anche essere usate (a tua scelta). Questi includono kdiff3 o xxdiff .

5
anthony

Utilizzando @ Peter.O's soluzione come base, l'ho riscritto per apportare una serie di modifiche.

enter image description here

  • Stampa ogni riga una sola volta, usando il colore per mostrare le differenze.
  • Non scrive alcun file temporaneo, eseguendo invece il piping di tutto.
  • Puoi fornire due nomi di file e confronterà le righe corrispondenti in ciascun file. ./hairOfTheDiff.sh file1.txt file2.txt
  • Altrimenti, se usi il formato originale (un singolo file con ogni seconda riga che deve essere confrontato con quello precedente) ora puoi semplicemente reindirizzarlo, non è necessario che esista un file da leggere. Dai un'occhiata a demo nel sorgente; questo può aprire le porte a fantasiose tubazioni per non aver bisogno di file anche per due input separati, usando paste e più descrittori di file.

Nessun punto culminante indica che il personaggio era in entrambe le righe, il momento saliente indica che era nel primo e il rosso indica che era nel secondo.

I colori sono modificabili attraverso le variabili nella parte superiore dello script e puoi persino rinunciare completamente ai colori usando caratteri normali per esprimere le differenze.

#!/bin/bash

same='-' #unchanged
up='△' #exists in first line, but not in second 
down='▽' #exists in second line, but not in first
reset=''

reset=$'\e[0m'
same=$reset
up=$reset$'\e[1m\e[7m'
down=$reset$'\e[1m\e[7m\e[31m'

timeout=1


if [[ "$1" != '' ]]
then
    paste -d'\n' "$1" "$2" | "$0"
    exit
fi

function demo {
    "$0" <<EOF
Paris in the spring 
Paris in the the spring
A cat on a hot tin roof.
a cant on a hot in roof
the quikc brown box jupps ober the laze dogs 
The quickbrown fox jumps over the lazy dogs
EOF
}

# Change \x20 to \x02 to simplify parsing diff's output,
#+   then change \x02 back to \x20 for the final output. 
# Change \x09 to \x01 to simplify parsing diff's output, 
#+   then change \x01 into → U+1F143 (Squared Latin Capital Letter T)
function input {
    sed \
        -e "s/\x09/\x01/g" \
        -e "s/\x20/\x02/g" \
        -e "s/\(.\)/\1\n/g"
}
function output {
    sed -n \
        -e "s/\x01/→/g" \
        -e "s/\x02/ /g" \
        -e "s/^\(.\) *\x3C$/\1 \x3C  /g" \
        -e "s/\(.\) *\(.\) \(.\)$/\1\2\3/p"
}

ifs="$IFS"
IFS=$'\n'
demo=true

while IFS= read -t "$timeout" -r a
do
    demo=false
    IFS= read -t "$timeout" -r b
    if [[ $? -ne 0 ]]
    then
        echo 'No corresponding line to compare with' > /dev/stderr
        exit 1
    fi

    diff --text -yt -W 19  \
        <(echo "$a" | input) \
        <(echo "$b" | input) \
    | \
    output | \
    {
        type=''
        buf=''
        while read -r line
        do
            if [[ "${line:1:1}" != "$type" ]]
            then
                if [[ "$type" = '|' ]]
                then
                    type='>'
                    echo -n "$down$buf"
                    buf=''
                fi

                if [[ "${line:1:1}" != "$type" ]]
                then
                    type="${line:1:1}"

                    echo -n "$type" \
                        | sed \
                            -e "s/[<|]/$up/" \
                            -e "s/>/$down/" \
                            -e "s/ /$same/"
                fi
            fi

            case "$type" in
            '|')
                buf="$buf${line:2:1}"
                echo -n "${line:0:1}"
                ;;
            '>')
                echo -n "${line:2:1}"
                ;;
            *)
                echo -n "${line:0:1}"
                ;;
            esac
        done

        if [[ "$type" = '|' ]]
        then
            echo -n "$down$buf"
        fi
    }

    echo -e "$reset"
done

IFS="$ifs"

if $demo
then
    demo
fi
4
Hashbrown

Ecco un semplice one-liner:

diff -y <(cat a.txt | sed -e 's/,/\n/g') <(cat b.txt | sed -e 's/,/\n/g')

L'idea è di sostituire le virgole (o qualunque delimitatore che si desidera utilizzare) con le nuove righe usando sed. diff quindi si occupa di tutto il resto.

3
user82160
  • xxdiff: un altro strumento è xxdiff (GUI), che deve essere installato per primo.
  • foglio di calcolo: per i dati del database, un foglio di calcolo da .csv è facilmente realizzabile e una formula (A7==K7) ? "" : "diff" o simile inserito e copiato e incollato.
2
user unknown

Se sto leggendo correttamente la tua domanda, utilizzo diff -y per questo tipo di cose.

Rende molto più semplice confrontare un confronto fianco a fianco per scoprire quali linee stanno gettando le differenze.

1
rfelsburg

Sulla riga di comando, vorrei assicurarmi di aggiungere nuove righe giudiziose prima di confrontare i file. Puoi usare sed, awk, Perl o qualsiasi altra cosa per aggiungere interruzioni di linea in qualche modo sistematico - assicurati di non aggiungere troppi però.

Ma trovo che il migliore sia usare vim in quanto mette in evidenza le differenze di Word. vim è buono se non ci sono troppe differenze e le differenze sono semplici.

1
asoundmove

Ho avuto lo stesso problema e l'ho risolto con PHP Fine Diff , uno strumento online che ti consente di specificare la granularità. So che tecnicamente non è uno strumento * nix, ma non volevo davvero scaricare un programma solo per fare una differenza a livello di personaggio una tantum.

1
pillravi

kdiff sta diventando il visualizzatore di differenze GUI standard su Linux. È simile a xxdiff , ma penso che kdiff3 sia migliore. Fa molte cose bene, inclusa la tua richiesta di mostrare "differenze di caratteri esatte tra due righe in determinati file".

1
Faheem Mitha