web-dev-qa-db-ja.com

行内の差分

SQLダンプがいくつかあり、それらの違いを調べています。 diffは明らかに2行の違いを示すことができますが、コンマ区切り値の長いリストのどの値が実際に行の違いを引き起こしているのかを見つけようと努力しています。

特定のファイルの2行間の正確な文字の違いを指摘するには、どのツールを使用できますか?

120
user394

wdiff があり、そのためのWord-diffがあります。

デスクトップでは、 meld を使用すると、行内の違いを強調できます。

96
alex

Git-diffを使用する別の方法:

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

差分の位置に関心がない場合は、grep -v。

31
Deepak

これにはvimdiffを使用しました。

ここにスクリーンショットがあります (私のものではありません)かなり目立つ1つまたは2つの文字の小さな違いを示しています。 A クイックチュートリアルも

24
Mark McKinstry

これは、「あなたを噛んだ犬の毛」の方法です...
diffによって、この時点に到達しました。それを使ってさらに先へ...

これは、横断抽出ラインのペアを使用した出力です... はタブを示します

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 
║  ║   ^ ║      ║     ║    ║          ║     ^

ここにスクリプトがあります..どういうわけか、ラインペアをフェレットアウトする必要があるだけです。スクリプトは私にとって、1日で十分でした:) ..それは十分に単純であるに違いないと思いますが、私はコーヒーブレークの予定です....

#
# 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 は実際、ファイルを1単語ずつ比較する非常に古い方法です。ファイルを再フォーマットし、diffを使用して違いを見つけ、それを再び渡すことで機能しました。私自身、コンテキストを追加することを提案しました。そのため、単語ごとの比較ではなく、各単語を他の「コンテキスト」単語で囲んで比較します。これにより、diffはファイル内の共通のパッセージで自分自身をよりよく同期させることができます。特に、ファイルがほとんど異なり、一般的な単語のブロックがわずかしかない場合にそうです。たとえば、盗用や再利用のためにテキストを比較する場合などです。

dwdiff は後でwdiffから作成されました。 Butdwdiffは、そのテキストの再フォーマット機能を使用して、dwfilterに効果をもたらします。これは優れた開発です。つまり、1つのテキストを別のテキストと一致するように再フォーマットし、行ごとのグラフィカルなdiff表示機能を使用してそれらを比較できます。たとえば、 "diffuse"グラフィカルdiffで使用すると...

dwfilter file1 file2 diffuse -w

これにより、file1file2の形式に再フォーマットされ、視覚的な比較のためにdiffuseに渡されます。 file2は変更されていないため、diffuseでWordの相違点を直接編集およびマージできます。 file1を編集する場合は、-rを追加して、再フォーマットするファイルを逆にすることができます。試してみてください。非常に強力です。

グラフィカルなdiff(上記を参照)の好みは diffuse です。また、スタンドアロンのpythonプログラムです。これは、他のUNIXシステムに簡単にインストールして配布できることを意味します。

他のグラフィカルなdiffには多くの依存関係があるようですが、使用することもできます(選択)。これらには kdiff3 または xxdiff が含まれます。

5
anthony

@ Peter.Oの solution を基礎として使用して、多くの変更を加えるために書き直しました。

enter image description here

  • すべての行を1回だけ印刷し、色を使用して違いを示します。
  • 一時ファイルを書き込まず、代わりにすべてをパイプします。
  • 2つのファイル名を指定すると、各ファイルの対応する行が比較されます。 ./hairOfTheDiff.sh file1.txt file2.txt
  • それ以外の場合、元の形式(2行ごとに1つ前のファイルと比較する必要がある単一のファイル)を使用する場合は、単純にパイプで接続するだけで、読み取るファイルは存在しません。ソースのdemoを見てください。これは、pasteおよび複数のファイル記述子を使用して、2つの別々の入力用のファイルも必要としないために、空想的な配管への扉を開くかもしれません。

ハイライトなしは、文字が両方の行にあることを意味し、ハイライトは最初の行にあることを意味し、赤は2番目の行にあることを意味します。

色はスクリプトの上部にある変数を介して変更でき、通常の文字を使用して違いを表現することで色を完全に無視することもできます。

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

ここに簡単なワンライナーがあります:

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

アイデアは、コンマ(または使用したい区切り文字)をsedを使用する改行で置き換えることです。 diffが残りを処理します。

3
user82160
  • xxdiff:別のツールはxxdiff(GUI)で、最初にインストールする必要があります。
  • スプレッドシート:データベースデータの場合、.csvは簡単に作成でき、式(A7==K7) ? "" : "diff"または同様のものを挿入し、コピーして貼り付けます。
2
user unknown

あなたの質問を正しく読んでいる場合は、diff -yこの種のもののため。

並べて比較することで、どの行が違いを引き起こしているかを見つけるのがはるかに簡単になります。

1
rfelsburg

コマンドラインでは、ファイルを比較する前に、賢明な改行を確実に追加します。 sed、awk、Perlなどを使用して、何らかの体系的な方法で改行を追加できます。ただし、追加しすぎないようにしてください。

しかし、Wordの違いが強調されているvimを使用するのが最善だと思います。 vimは、違いが多すぎず、違いが単純な場合に適しています。

1
asoundmove

私は同じ問題を抱えており、粒度を指定できるオンラインツール PHP Fine Diff で解決しました。技術的には* nixツールではないことは知っていますが、1回限りの文字レベルの差分を行うためだけにプログラムをダウンロードしたくありませんでした。

1
pillravi

kdiff は、Linuxの標準GUI差分ビューアになりつつあります。 xxdiff に似ていますが、kdiff3の方が良いと思います。 「特定のファイルの2行間の正確な文字の違い」を表示するというリクエストを含め、多くのことがうまくいきます。

1
Faheem Mitha