web-dev-qa-db-fra.com

diff dans une ligne

J'ai quelques vidages sql que je regarde les différences entre. diff peut évidemment me montrer la différence entre deux lignes, mais je me rends fou en essayant de trouver quelles valeurs dans la longue liste de valeurs séparées par des virgules sont en fait celles qui rendent les lignes différentes.

Quel outil puis-je utiliser pour signaler les différences de caractères exactes entre deux lignes dans certains fichiers?

120
user394

Il y a wdiff , le Word-diff pour cela.

Sur le bureau, meld peut mettre en évidence les différences au sein d'une ligne pour vous.

96
alex

Juste une autre méthode utilisant git-diff:

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

grep -v s'il n'est pas intéressé par les positions des diffs.

31
Deepak

J'ai utilisé vimdiff pour cela.

Voici une capture d'écran (pas le mien) montrant des différences mineures d'un ou deux caractères qui se démarquent assez bien. A tutoriel rapide aussi .

24
Mark McKinstry

Voici une méthode "..hair du chien qui vous a mordu" ...
diff vous a amené à ce point; utilisez-le pour aller plus loin ...

Voici le résultat de l'utilisation des paires de lignes d'échantillonnage ... indique un 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 
║  ║   ^ ║      ║     ║    ║          ║     ^

Voici le script .. Vous avez juste besoin de dénicher les paires de lignes d'une manière ou d'une autre .. (J'ai utilisé diff une seule fois (deux fois?) Avant aujourd'hui, donc je ne connais pas ses nombreuses options, et trier les options pour cela le script était suffisant pour moi, pour une journée :) .. Je pense que ça doit être assez simple, mais je dois faire une pause café ....

#
# 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 est en fait une très ancienne méthode de comparaison de fichiers mot par mot. Cela a fonctionné en reformatant les fichiers, puis en utilisant diff pour trouver les différences et les transmettre à nouveau. J'ai moi-même suggéré d'ajouter du contexte, de sorte que plutôt que de comparer mot par mot, il le fasse avec chaque mot entouré d'autres mots de "contexte". Cela permet au diff de se synchroniser beaucoup mieux sur les passages communs dans les fichiers, surtout lorsque les fichiers sont généralement différents avec seulement quelques blocs de mots communs. Par exemple lors de la comparaison de texte pour le plagiat ou la réutilisation.

dwdiff a été créé ultérieurement à partir de wdiff. Mais dwdiff utilise cette fonction de reformatage du texte à bon escient dans dwfilter. C'est un grand développement - cela signifie que vous pouvez reformater un texte pour qu'il corresponde à un autre, puis les comparer à l'aide de n'importe quel afficheur graphique diff ligne par ligne. Par exemple, en l'utilisant avec un diff graphique "diffus" ...

dwfilter file1 file2 diffuse -w

Cette reformate file1 au format file2 et donne cela à diffuse pour une comparaison visuelle. file2 n'est pas modifié, vous pouvez donc modifier et fusionner les différences Word directement dans diffuse. Si vous souhaitez modifier file1, vous pouvez ajouter -r pour inverser le fichier reformaté. Essayez-le et vous verrez qu'il est extrêmement puissant!

Ma préférence pour le diff graphique (illustré ci-dessus) est diffuse car il semble beaucoup plus propre et plus utile. Il s'agit également d'un programme autonome python, ce qui signifie qu'il est facile à installer et à distribuer sur d'autres systèmes UNIX.

D'autres différences graphiques semblent avoir beaucoup de dépendances, mais peuvent également être utilisées (à votre choix). Ceux-ci inclus kdiff3 ou xxdiff .

5
anthony

En utilisant solution de @ Peter.O comme base, je l'ai réécrit pour apporter un certain nombre de modifications.

enter image description here

  • Il imprime chaque ligne une seule fois, en utilisant la couleur pour vous montrer les différences.
  • Il n'écrit aucun fichier temporaire, tout passe à la place.
  • Vous pouvez fournir deux noms de fichiers et cela comparera les lignes correspondantes dans chaque fichier. ./hairOfTheDiff.sh file1.txt file2.txt
  • Sinon, si vous utilisez le format d'origine (un seul fichier avec une ligne sur deux devant être comparée à la précédente), vous pouvez maintenant simplement le canaliser, aucun fichier n'a besoin d'exister pour être lu. Jetez un œil à demo dans la source; cela peut ouvrir la porte à une tuyauterie sophistiquée afin de ne pas avoir besoin de fichiers pour deux entrées distinctes également, en utilisant paste et plusieurs descripteurs de fichiers.

Aucun surlignage signifie que le personnage était dans les deux lignes, surlignage signifie qu'il était dans la première et rouge signifie qu'il était dans la seconde.

Les couleurs sont modifiables via des variables en haut du script et vous pouvez même renoncer entièrement aux couleurs en utilisant des caractères normaux pour exprimer les différences.

#!/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

Voici une simple doublure:

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

L'idée est de remplacer les virgules (ou le délimiteur que vous souhaitez utiliser) par des sauts de ligne en utilisant sed. diff s'occupe ensuite du reste.

3
user82160
  • xxdiff: Un autre outil est xxdiff (GUI), qui doit d'abord être installé.
  • feuille de calcul: pour les données de base de données, une feuille de calcul de .csv se fait facilement et une formule (A7==K7) ? "" : "diff" ou similaire inséré et copié-collé.
2
user unknown

Si je lis correctement votre question, j'utilise diff -y pour ce genre de chose.

Cela rend la comparaison d'une comparaison côte à côte beaucoup plus simple pour trouver les lignes qui génèrent les différences.

1
rfelsburg

Sur la ligne de commande, je m'assurerais d'ajouter de nouvelles lignes judicieuses avant de comparer les fichiers. Vous pouvez utiliser sed, awk, Perl ou quoi que ce soit vraiment pour ajouter des sauts de ligne d'une manière systématique - assurez-vous de ne pas en ajouter trop.

Mais je trouve que le mieux est d'utiliser vim car il met en évidence les différences Word. vim est bon s'il n'y a pas trop de différences et que les différences sont simples.

1
asoundmove

J'ai eu le même problème et l'ai résolu avec PHP Fine Diff , un outil en ligne qui vous permet de spécifier la granularité. Je sais que ce n'est pas techniquement un outil * nix, mais je ne voulais pas vraiment télécharger un programme juste pour faire une différence unique au niveau des caractères.

1
pillravi

kdiff devient le visualiseur de différences GUI standard sous Linux. Il est similaire à xxdiff , mais je pense que kdiff3 est meilleur. Il fait bien des choses, y compris votre demande d'afficher "les différences de caractères exactes entre deux lignes dans certains fichiers".

1
Faheem Mitha