beda dalam satu garis

113

Saya punya beberapa dump sql yang saya cari perbedaannya. diffjelas dapat menunjukkan kepada saya perbedaan antara dua baris, tapi saya mendorong diri saya mencoba untuk menemukan nilai mana dalam daftar panjang nilai yang dipisahkan oleh koma yang sebenarnya menyebabkan garis menjadi berbeda.

Alat apa yang dapat saya gunakan untuk menunjukkan perbedaan karakter yang tepat antara dua baris dalam file tertentu?

pengguna394
sumber
superuser.com/questions/496415/… | stackoverflow.com/questions/1342256/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Jawaban:

93

Ada wdiff , kata-diff untuk itu.

Di desktop, berbaur dapat menyoroti perbedaan dalam satu baris untuk Anda.

alex
sumber
8
Wdiff berwarna:wdiff -w "$(tput bold;tput setaf 1)" -x "$(tput sgr0)" -y "$(tput bold;tput setaf 2)" -z "$(tput sgr0)" file1 file2
l0b0
47
Untuk warna, instal colordiff , lalu lakukan:wdiff a b | colordiff
philfreo
Meld sebenarnya sangat lambat (menit) untuk menunjukkan perbedaan intra-line antara file berbasis baris.
Dan Dascalescu
Ada juga dwdiffalat yang sebagian besar kompatibel dengan wdifftetapi juga mendukung keluaran berwarna dan mungkin beberapa fitur lainnya. Dan itu lebih tersedia di beberapa distribusi Linux seperti Arch.
MarSoft
4
wdiff -n a b | colordiff, menyarankan man colordiff.
Camille Goudeseune
25

Hanya metode lain menggunakan git-diff:

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

grep -v jika tidak tertarik pada posisi diffs.

Deepak
sumber
2
Ini persis perilaku yang saya coba tiru - tidak menyadari saya bisa menggunakan git-diff tanpa salah satu file diindeks.
spinup
1
--word-diff adalah opsi utama di sini. Terima kasih!
user2707671
1
--no-index hanya diperlukan jika Anda berada di direktori kerja git dan foo dan bar juga.
xn.
22

Saya sudah menggunakan vimdiffini.

Berikut adalah tangkapan layar (bukan milik saya) yang menunjukkan sedikit perbedaan satu atau dua karakter yang cukup baik. Sebuah tutorial cepat juga .

Mark McKinstry
sumber
Dalam kasus saya tidak dapat melihat perbedaannya sehingga membuka file di gvim -d f1 f2 garis panjang tertentu keduanya disorot sebagai berbeda namun perbedaan yang sebenarnya adalah ekstra disorot dalam warna merah
zzapper
Saya telah menggunakan vim selamanya, tetapi tidak tahu tentang vimdiff!
mitchus
Dan ada diffchar.vim untuk diff tingkat karakter.
2
Seperti saya suka vim dan vimdiff, algoritma vimdiff untuk menyoroti perbedaan dalam sebuah garis cukup mendasar. Tampaknya hanya menghapus awalan umum dan akhiran, dan menyoroti semuanya sebagai berbeda. Ini berfungsi jika semua karakter yang diubah dikelompokkan bersama, tetapi jika mereka menyebar tidak berfungsi dengan baik. Ini juga mengerikan untuk teks yang dibungkus kata.
Laurence Gonsalves
Untuk garis panjang seperti pada OP vimdiff -c 'set wrap' -c 'wincmd w' -c 'set wrap' a b,, sarankan stackoverflow.com/a/45333535/2097284 .
Camille Goudeseune
6

Ini adalah metode "..hair dari anjing yang menggigitmu" ...
diffmembuat Anda sampai pada titik ini; gunakan untuk membawa Anda lebih jauh ...

Berikut ini adalah output dari menggunakan pasangan garis sampel ... menunjukkan 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 
║  ║   ^ ║      ║     ║    ║          ║     ^

Ini skripnya .. Anda hanya perlu menemukan pasangan garisnya entah bagaimana .. (Saya telah menggunakan diff hanya sekali (dua kali?) Sebelum hari ini, jadi saya tidak tahu banyak pilihannya, dan memilah opsi untuk ini script sudah cukup untuk saya, untuk satu hari :) .. Saya pikir itu harus cukup sederhana, tetapi saya harus istirahat kopi ....

#
# 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
#
Peter.O
sumber
4

wdiffsebenarnya adalah metode yang sangat lama membandingkan file kata per kata. Ini berfungsi dengan memformat ulang file, kemudian gunakan diffuntuk menemukan perbedaan dan meneruskannya kembali. Saya sendiri menyarankan untuk menambahkan konteks, daripada membandingkan kata per kata, ia melakukannya dengan setiap kata dikelilingi oleh kata-kata 'konteks' lainnya. Itu memungkinkan diff untuk menyinkronkan dirinya sendiri pada bagian-bagian umum dalam file jauh lebih baik, terutama ketika file sebagian besar berbeda dengan hanya beberapa blok kata-kata umum. Misalnya ketika membandingkan teks untuk plagiarisme, atau digunakan kembali.

dwdiffkemudian dibuat dari wdiff. Tetapi dwdiff gunakan fungsi pemformatan ulang teks tersebut untuk efek yang baik di dwfilter. Ini adalah pengembangan yang luar biasa - ini artinya Anda dapat memformat ulang satu teks untuk mencocokkan yang lain, dan kemudian membandingkannya dengan menggunakan penampil gambar grafik baris per baris. Sebagai contoh, menggunakannya dengan ...

dwfilter file1 file2 diffuse -w

Ini memformat file1ke format file2dan memberikannya diffuseuntuk perbandingan visual. file2belum dimodifikasi, sehingga Anda dapat mengedit dan menggabungkan perbedaan kata ke dalamnya secara langsung di diffuse. Jika Anda ingin mengedit file1, Anda dapat menambahkan -runtuk membalikkan file mana yang diformat ulang. Cobalah dan Anda akan menemukan itu sangat kuat!

Preferensi saya untuk perbedaan grafis (ditunjukkan di atas) adalah diffusekarena terasa jauh lebih bersih dan lebih bermanfaat. Juga merupakan program python mandiri, yang berarti mudah untuk menginstal dan mendistribusikan ke sistem UNIX lainnya.

Difer grafis lain tampaknya memiliki banyak ketergantungan, tetapi juga dapat digunakan (pilihan Anda). Ini termasuk kdiff3atau xxdiff.

anthony
sumber
4

Menggunakan solusi @ Peter.O sebagai dasar, saya menulis ulang untuk membuat sejumlah perubahan.

masukkan deskripsi gambar di sini

  • Hanya mencetak setiap baris sekali, menggunakan warna untuk menunjukkan perbedaan.
  • Itu tidak menulis file temp, memipiskan semuanya.
  • Anda dapat memberikan dua nama file dan itu akan membandingkan baris yang sesuai di setiap file. ./hairOfTheDiff.sh file1.txt file2.txt
  • Jika tidak, jika Anda menggunakan format asli (satu file dengan setiap baris kedua perlu dibandingkan dengan yang sebelumnya), Anda sekarang dapat memasukkannya ke dalam file, tidak perlu ada file untuk dibaca. Lihatlah demodi sumbernya; ini dapat membuka pintu untuk pemipaan agar tidak perlu file untuk dua input terpisah juga, menggunakan pastedan beberapa file-deskriptor.

Tidak ada highlight berarti karakter berada di kedua baris, highlight berarti berada di baris pertama, dan merah berarti di baris kedua.

Warna dapat diubah melalui variabel di bagian atas skrip dan Anda bahkan dapat melepaskan warna sepenuhnya dengan menggunakan karakter normal untuk mengekspresikan perbedaan.

#!/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
Hashbrown
sumber
3

Berikut ini satu kalimat sederhana:

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

Idenya adalah untuk mengganti koma (atau pembatas mana pun yang ingin Anda gunakan) dengan menggunakan baris baru sed. diffkemudian mengurus sisanya.


sumber
2
  • xxdiff: Alat lain adalah xxdiff (GUI), yang harus diinstal terlebih dahulu.
  • spreadsheet: Untuk data database, spreadsheet dari .csvmudah dibuat, dan formula (A7==K7) ? "" : "diff"atau yang serupa dimasukkan, dan disalin-tempel.
Pengguna tidak diketahui
sumber
1
xxdiff terlihat seperti tahun 80-an. Meld terlihat jauh lebih baik tetapi sangat lambat untuk file seperti CSV. Saya telah menemukan Diffuse sebagai alat diff Linux tercepat.
Dan Dascalescu
@DanDascalescu: Alat yang menyelesaikan pekerjaan selalu terlihat baik-baik saja, tidak peduli berapa pun usianya. Satu lagi, saya kadang-kadang digunakan, tetapi tidak diinstal untuk mengujinya dengan panjang, data kolom, adalah tkdiff .
pengguna tidak diketahui
Apakah tampilan xxdiff memindahkan baris ? Atau apakah itu hanya menunjukkan baris yang hilang di satu file dan yang ditambahkan di yang lain? (Saya mencoba membangun xxdiff tetapi qmake gagal dan saya melihat mereka tidak repot-repot menerbitkan paket Debian).
Dan Dascalescu
@DanDascalescu: Hari ini, saya hanya menginstal tkdiff.
pengguna tidak diketahui
1

Pada baris perintah, saya akan memastikan saya menambahkan baris baru yang bijaksana sebelum membandingkan file. Anda dapat menggunakan sed, awk, perl atau apa pun untuk menambahkan jeda baris dengan cara sistematis - pastikan untuk tidak menambahkan terlalu banyak.

Tapi saya menemukan yang terbaik adalah menggunakan vim karena menyoroti perbedaan kata. vim baik jika tidak terlalu banyak perbedaan dan perbedaannya sederhana.

pindahkan
sumber
Meskipun tidak benar-benar jawaban atas pertanyaan, teknik ini agak efisien untuk belajar tentang perbedaan kecil dalam antrean panjang.
jknappen
1

kdiff3 menjadi penampil diff GUI standar di Linux. Ini mirip dengan xxdiff , tapi saya pikir kdiff3 lebih baik. Itu melakukan banyak hal dengan baik, termasuk permintaan Anda untuk menunjukkan "perbedaan karakter yang tepat antara dua baris dalam file tertentu".

Faheem Mitha
sumber
KDiff3 sangat lambat untuk menyoroti perbedaan sebaris dalam file CSV. Saya tidak akan merekomendasikannya.
Dan Dascalescu
1

Jika saya membaca pertanyaan Anda dengan benar, saya gunakan diff -yuntuk hal semacam ini.

Itu membuat membandingkan perbandingan berdampingan jauh lebih mudah untuk menemukan garis mana yang melempar perbedaan.

rfelsburg
sumber
1
Ini tidak menyoroti perbedaan di dalam garis. Jika Anda memiliki garis panjang, menyakitkan untuk melihat perbedaannya. wdiff, git diff --word-diff, vimgit, meld, kbdiff3, tkdiff semua melakukan ini.
user2707671
1

Saya memiliki masalah yang sama dan menyelesaikannya dengan PHP Fine Diff , alat online yang memungkinkan Anda menentukan rincian. Saya tahu ini bukan alat * nix secara teknis, tetapi saya tidak benar-benar ingin mengunduh program hanya untuk melakukan satu kali, tingkat karakter berbeda.

pillravi
sumber
Beberapa pengguna tidak dapat mengunggah file sensitif atau besar ke alat daring acak. Ada banyak alat yang menunjukkan perbedaan level garis tanpa mengurangi privasi Anda.
Dan Dascalescu
Ya ada. Tetapi untuk diff yang tidak mengandung informasi sensitif, alat online bisa menjadi solusi yang baik.
pillravi
Alat beda online juga tidak mendukung integrasi baris perintah. Anda tidak dapat menggunakannya dari aliran kontrol versi Anda. Mereka juga jauh lebih rumit untuk digunakan (pilih file 1, pilih file 2, unggah) dan tidak dapat melakukan penggabungan.
Dan Dascalescu