Há wdiff , a palavra diff para isso.
Na área de trabalho, o meld pode destacar as diferenças dentro de uma linha para você.
Eu tenho alguns despejos de sql que eu estou olhando as diferenças entre. diff
pode obviamente me mostrar a diferença entre duas linhas, mas estou me deixando louca tentando descobrir quais valores na longa lista de valores separados por vírgula são aqueles que fazem com que as linhas sejam diferentes.
Qual ferramenta posso usar para apontar as diferenças de caracteres exatas entre duas linhas em certos arquivos?
Eu usei vimdiff
para isso.
Aqui está uma captura de tela (não minha) mostrando diferenças de um ou dois caracteres menores que se destaca muito bem. Um tutorial rápido também .
Apenas outro método usando o git-diff:
git diff -U0 --word-diff --no-index -- foo bar | grep -v ^@@
grep -v se não estiver interessado em posições dos diffs.
Aqui está um método "..cabelo do cão que mordeu você" ...
diff
chegou até você nesse ponto; use-o para ir mais longe ...
Aqui está a saída do uso dos pares de linhas de amostra ... ☻
indica uma 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
║ ║ ^ ║ ║ ║ ║ ║ ^
Aqui está o script .. Você só precisa descobrir os pares de linha de alguma forma .. (Eu usei diff apenas uma vez (duas vezes?) antes de hoje, então eu não sei suas muitas opções, e resolvendo o opções para este script foi o suficiente para mim, por um dia :) .. Eu acho que deve ser bastante simples, mas eu estou pronto para um coffee break ....
#
# 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/\(.\)/\n/g") \
<(echo "${pair[1]}" |sed -e "s/\x09/\x01/g" -e "s/\x20/\x02/g" -e "s/\(.\)/\n/g") \
|sed -e "s/\x01/☻/g" -e "s/\x02/ /g" \
|sed -e "s/^\(.\) *\x3C$/ \x3C /g" \
|sed -n "s/\(.\) *\(.\) \(.\)$//p" \
>"$workd/out"
# (gedit "$workd/out" &)
<"$workd/out" sed -e "s/^\(.\)..$//" |tr -d '\n' ;echo
<"$workd/out" sed -e "s/^..\(.\)$//" |tr -d '\n' ;echo
<"$workd/out" sed -e "s/^.\(.\).$//" -e "s/|/║/" -e "s/</^/" -e "s/>/v/" |tr -d '\n' ;echo
echo
((ix=0))
fi
done <"$ifile"
IFS="$ifs" ;set +f
exit
#
wdiff
é, na verdade, um método muito antigo de comparar arquivos palavra por palavra. Funcionou reformatando arquivos, depois usando diff
para encontrar diferenças e passá-las novamente. Eu mesmo sugeri adicionar contexto, de modo que, em vez de comparar palavra por palavra, ele faça isso com cada palavra cercada por outras palavras de "contexto". Isso permite que o diff se sincronize em passagens comuns em arquivos muito melhor, especialmente quando os arquivos são diferentes com apenas alguns blocos de palavras comuns. Por exemplo, ao comparar texto para plágio ou reutilização.
dwdiff
foi criado posteriormente a partir de wdiff
. Mas dwdiff
usa essa função de reformatação de texto com bom efeito em dwfilter
. Este é um ótimo desenvolvimento - significa que você pode reformatar um texto para corresponder a outro e, em seguida, compará-los usando qualquer visualizador gráfico de diferenças linha-a-linha. Por exemplo, usando-o com diff gráfico "difuso" ....
dwfilter file1 file2 diffuse -w
Isso reformata file1
para o formato de file2
e atribui isso a diffuse
para uma comparação visual. file2
não está modificado, portanto você pode editar e mesclar diferenças de palavras diretamente em diffuse
. Se você quiser editar file1
, você pode adicionar -r
para reverter qual arquivo é reformatado. Experimente e você vai achar que é extremamente poderoso!
Minha preferência pelo diff gráfico (mostrado acima) é diffuse
, pois parece muito mais limpo e útil. Também é um programa python autônomo, o que significa que é fácil de instalar e distribuir para outros sistemas UNIX.
Outros diffs gráficos parecem ter muitas dependências, mas também podem ser usados (você escolhe). Estes incluem kdiff3
ou xxdiff
.
Usando a solução do @Peter.O., como base, reescrevi-a para fazer uma série de alterações. p>
./hairOfTheDiff.shfile1.txtfile2.txt
nafonte;issopodeabriraportaparaaextravagânciadatubulação,afimdenãoprecisardearquivosparaduasentradasseparadas,usandodemo
eváriosdescritoresdearquivo.Nenhumdestaquesignificaqueopersonagemestavaemambasaslinhas,destaquesignificaqueestavanoprimeiroevermelhosignificaqueestavanosegundo.
Ascoressãoalteráveisatravésdevariáveisnotopodoscriptevocêpodeatémesmorenunciaràscoresinteiramenteusandocaracteresnormaisparaexpressardiferenças.
#!/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/\(.\)/\n/g"
}
function output {
sed -n \
-e "s/\x01/→/g" \
-e "s/\x02/ /g" \
-e "s/^\(.\) *\x3C$/ \x3C /g" \
-e "s/\(.\) *\(.\) \(.\)$//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
Se eu estou lendo sua pergunta corretamente, eu uso diff -y
para esse tipo de coisa.
Torna a comparação de uma comparação lado a lado muito mais simples para descobrir quais linhas estão jogando as diferenças.
.csv
é facilmente criada e uma fórmula (A7==K7) ? "" : "diff"
ou semelhante é inserida e copiada e colada. Aqui está uma simples anotação:
diff -y <(cat a.txt | sed -e 's/,/\n/g') <(cat b.txt | sed -e 's/,/\n/g')
A idéia é substituir vírgulas (ou qualquer delimitador que você queira usar) por novas linhas usando sed
. diff
cuida do resto.
Na linha de comando, eu me certificaria de adicionar novas linhas judiciosas antes de comparar os arquivos. Você pode usar sed, awk, perl ou qualquer coisa realmente para adicionar quebras de linha de alguma forma sistemática - certifique-se de não adicionar muitos.
Mas acho que o melhor é usar o vim para destacar as diferenças de palavras. O vim é bom se não houver muitas diferenças e as diferenças forem simples.
Eu tive o mesmo problema e resolvi com PHP Fine Diff , uma ferramenta on-line que permite para especificar a granularidade. Eu sei que não é tecnicamente uma ferramenta * nix, mas eu realmente não queria baixar um programa apenas para fazer um único diff de nível de caractere.
Tags command-line diff