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?
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.
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 .
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
#
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
.
En utilisant solution de @ Peter.O comme base, je l'ai réécrit pour apporter un certain nombre de modifications.
./hairOfTheDiff.sh file1.txt file2.txt
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
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.
.csv
se fait facilement et une formule (A7==K7) ? "" : "diff"
ou similaire inséré et copié-collé.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.
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.
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.