khác trong một dòng


113

Tôi có một số bãi sql mà tôi đang xem xét sự khác biệt giữa. diffRõ ràng có thể cho tôi thấy sự khác biệt giữa hai dòng, nhưng tôi đang cố gắng tìm kiếm những giá trị nào trong danh sách dài các giá trị được phân tách bằng dấu phẩy thực sự là những giá trị khiến các dòng khác nhau.

Tôi có thể sử dụng công cụ nào để chỉ ra sự khác biệt về ký tự chính xác giữa hai dòng trong một số tệp nhất định?


Câu trả lời:


93

wdiff , từ khác cho điều đó.

Trên máy tính để bàn, meld có thể làm nổi bật sự khác biệt trong một dòng cho bạn.


8
Màu wdiff:wdiff -w "$(tput bold;tput setaf 1)" -x "$(tput sgr0)" -y "$(tput bold;tput setaf 2)" -z "$(tput sgr0)" file1 file2
l0b0

47
Đối với màu sắc, cài đặt colordiff , sau đó làm:wdiff a b | colordiff
philfreo

Meld thực sự rất chậm (phút) khi hiển thị sự khác biệt giữa dòng giữa các tệp dựa trên dòng.
Dan Dascalescu

Ngoài ra còn có dwdiffcông cụ chủ yếu tương thích với wdiffnhưng cũng hỗ trợ đầu ra màu và có thể một số tính năng khác. Và nó có sẵn hơn trong một số bản phân phối Linux như Arch.
MarSoft

4
wdiff -n a b | colordiff, khuyên man colordiff.
Camille Goudeseune

25

Chỉ là một phương pháp khác sử dụng git-diff:

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

grep -v nếu không quan tâm đến vị trí của các khác biệt.


2
Đây chính xác là hành vi tôi đã cố gắng bắt chước - không nhận ra tôi có thể sử dụng git-diff mà không cần một trong các tệp được lập chỉ mục.
spinup

1
--word-diff là tùy chọn chính ở đây. Cảm ơn!
user2707671

1
--no-index chỉ được yêu cầu nếu bạn đang ở trong thư mục git làm việc và cả foo và bar cũng vậy.
xn.

22

Tôi đã sử dụng vimdiffcho việc này.

Đây là một ảnh chụp màn hình (không phải của tôi) cho thấy một hoặc hai sự khác biệt nhỏ của nhân vật nổi bật khá tốt. Một hướng dẫn nhanh quá .


Trong trường hợp của tôi không thể phát hiện ra sự khác biệt nên đã mở các tệp trong gvim -d f1 f2, các dòng dài cụ thể đều được tô sáng là khác nhau tuy nhiên sự khác biệt thực tế được tô sáng thêm bằng màu đỏ
zzapper

Tôi đã sử dụng vim mãi mãi, nhưng không biết gì về vimdiff!
mitchus

Và có diffchar.vim cho diffs cấp độ nhân vật.

2
Nhiều như tôi yêu vim và vimdiff, thuật toán của vimdiff để làm nổi bật sự khác biệt trong một dòng là khá cơ bản. Nó dường như chỉ loại bỏ tiền tố và hậu tố phổ biến, và làm nổi bật mọi thứ giữa là khác nhau. Điều này hoạt động nếu tất cả các nhân vật thay đổi được nhóm lại với nhau, nhưng nếu chúng được trải ra thì nó không hoạt động tốt. Nó cũng khủng khiếp cho văn bản bao bọc từ.
Laurence Gonsalves

Đối với các dòng dài như trong OP vimdiff -c 'set wrap' -c 'wincmd w' -c 'set wrap' a b, đề xuất stackoverflow.com/a/45333535/2097284 .
Camille Goudeseune

6

Đây là một phương pháp ".. chó của bạn cắn bạn" ...
diff đưa bạn đến điểm này; sử dụng nó để đưa bạn đi xa hơn ...

Đây là đầu ra từ việc sử dụng các cặp dòng mẫu ... biểu thị 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 
║  ║   ^ ║      ║     ║    ║          ║     ^

Đây là kịch bản .. Bạn chỉ cần tìm ra các cặp dòng bằng cách nào đó .. (Tôi đã sử dụng diff chỉ một lần (hai lần?) Trước ngày hôm nay, vì vậy tôi không biết nhiều tùy chọn của nó và sắp xếp các tùy chọn cho việc này kịch bản là đủ cho tôi, trong một ngày :) .. Tôi nghĩ nó phải đủ đơn giản, nhưng tôi sắp nghỉ cà phê ....

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

4

wdiffthực sự là một phương pháp rất cũ để so sánh các tập tin từng chữ một. Nó hoạt động bằng cách định dạng lại các tệp, sau đó sử dụng diffđể tìm sự khác biệt và gửi lại. Bản thân tôi đề nghị thêm ngữ cảnh, để thay vì so sánh từng từ, nó thực hiện với từng từ được bao quanh bởi các từ 'ngữ cảnh' khác. Điều đó cho phép diff tự đồng bộ hóa trên các đoạn phổ biến trong các tệp tốt hơn nhiều, đặc biệt là khi các tệp hầu hết khác nhau chỉ với một vài khối từ phổ biến. Ví dụ: khi so sánh văn bản cho đạo văn, hoặc sử dụng lại.

dwdiffsau đó được tạo ra từ wdiff. Nhưng dwdiff sử dụng chức năng định dạng lại văn bản để có hiệu quả tốt trong dwfilter. Đây là một sự phát triển tuyệt vời - nó có nghĩa là bạn có thể định dạng lại một văn bản để khớp với một văn bản khác, và sau đó so sánh chúng bằng cách sử dụng bất kỳ trình hiển thị khác biệt đồ họa từng dòng. Ví dụ: sử dụng nó với "diffuse" đồ họa diff ....

dwfilter file1 file2 diffuse -w

Điều này định dạng lại file1định dạng file2và đưa ra để diffuseso sánh trực quan. file2không được sửa đổi, vì vậy bạn có thể chỉnh sửa và hợp nhất các từ khác nhau vào nó trực tiếp diffuse. Nếu bạn muốn chỉnh sửa file1, bạn có thể thêm -rđể đảo ngược tập tin nào được định dạng lại. Hãy thử nó và bạn sẽ thấy nó vô cùng mạnh mẽ!

Sở thích của tôi cho khác biệt đồ họa (hiển thị ở trên) là diffuse vì nó cảm thấy sạch sẽ hơn và hữu ích hơn. Ngoài ra, đây là một chương trình python độc lập, có nghĩa là nó dễ dàng cài đặt và phân phối cho các hệ thống UNIX khác.

Khác biệt đồ họa khác dường như có rất nhiều phụ thuộc, nhưng cũng có thể được sử dụng (bạn chọn). Chúng bao gồm kdiff3hoặc xxdiff.


4

Sử dụng giải pháp của @ Peter.O làm cơ sở, tôi viết lại nó để thực hiện một số thay đổi.

nhập mô tả hình ảnh ở đây

  • Nó chỉ in mỗi dòng một lần, sử dụng màu sắc để cho bạn thấy sự khác biệt.
  • Nó không viết bất kỳ tập tin tạm thời nào, thay vào đó là mọi thứ.
  • Bạn có thể cung cấp hai tên tệp và nó sẽ so sánh các dòng tương ứng trong mỗi tệp. ./hairOfTheDiff.sh file1.txt file2.txt
  • Mặt khác, nếu bạn sử dụng định dạng gốc (một tệp duy nhất với mỗi dòng thứ hai cần được so sánh với tệp trước đó) thì bây giờ bạn có thể chỉ cần đặt nó vào, không cần phải đọc tệp. Hãy xem demotrong nguồn; điều này có thể mở ra cánh cửa cho các đường ống ưa thích để không cần các tệp cho hai đầu vào riêng biệt, sử dụng pastevà nhiều mô tả tệp.

Không có điểm nổi bật có nghĩa là nhân vật ở cả hai dòng, nổi bật có nghĩa là nó ở đầu tiên và màu đỏ có nghĩa là nó ở thứ hai.

Màu sắc có thể thay đổi thông qua các biến ở đầu tập lệnh và bạn thậm chí có thể từ bỏ màu hoàn toàn bằng cách sử dụng các ký tự bình thường để thể hiện sự khác biệt.

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

3

Đây là một lót đơn giản:

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

Ý tưởng là thay thế dấu phẩy (hoặc bất kỳ dấu phân cách nào bạn muốn sử dụng) bằng các dòng mới sử dụng sed. diffsau đó chăm sóc phần còn lại.


2
  • xxdiff: Một công cụ khác là xxdiff (GUI), trước tiên phải được cài đặt.
  • bảng tính: Đối với dữ liệu cơ sở dữ liệu, một bảng tính từ .csvdễ dàng được tạo và một công thức (A7==K7) ? "" : "diff"hoặc tương tự được chèn và dán sao chép.

1
xxdiff trông giống như những năm 80 Meld trông tốt hơn nhiều nhưng nó cực kỳ chậm đối với các tệp giống như CSV. Tôi đã tìm thấy Diffuse là công cụ tìm khác biệt nhanh nhất của Linux.
Dan Dascalescu

@DanDascalescu: Một công cụ hoàn thành công việc trông luôn ổn, bất kể nó trông như thế nào. Một cái khác, tôi thỉnh thoảng sử dụng, nhưng không được cài đặt để kiểm tra nó với dữ liệu cột dài, là tkdiff .
người dùng không xác định

Xxdiff có hiển thị các dòng di chuyển không? Hay nó chỉ hiển thị một dòng bị thiếu trong một tệp và một dòng được thêm vào trong một tệp khác? (Tôi đã thử xây dựng xxdiff nhưng qmake không thành công và tôi thấy họ không bận tâm xuất bản gói Debian).
Dan Dascalescu

@DanDascalescu: Hôm nay, tôi chỉ cài đặt tkdiff.
người dùng không xác định

1

Trên dòng lệnh, tôi sẽ đảm bảo rằng tôi thêm các dòng mới hợp lý trước khi so sánh các tệp. Bạn có thể sử dụng sed, awk, perl hoặc bất cứ thứ gì thực sự để thêm ngắt dòng theo một cách nào đó có hệ thống - đảm bảo không thêm quá nhiều mặc dù.

Nhưng tôi thấy tốt nhất là sử dụng vim vì nó làm nổi bật sự khác biệt từ. vim là tốt nếu không có quá nhiều sự khác biệt và sự khác biệt là đơn giản.


Mặc dù không thực sự là một câu trả lời cho câu hỏi, kỹ thuật này khá hiệu quả để tìm hiểu về những khác biệt nhỏ trong các dòng dài.
jknappen 4/2/2015

1

kdiff3 đang trở thành trình xem khác biệt GUI tiêu chuẩn trên Linux. Nó tương tự như xxdiff , nhưng tôi nghĩ kdiff3 tốt hơn. Nó thực hiện nhiều điều tốt, bao gồm cả yêu cầu của bạn để hiển thị "sự khác biệt chính xác giữa hai dòng trong một số tệp nhất định".


KDiff3 cực kỳ chậm để làm nổi bật sự khác biệt nội tuyến trong các tệp CSV. Tôi sẽ không đề nghị nó.
Dan Dascalescu

1

Nếu tôi đọc chính xác câu hỏi của bạn, tôi sử dụng diff -y cho loại điều này.

Nó làm cho việc so sánh một so sánh cạnh nhau đơn giản hơn nhiều để tìm ra dòng nào đang tạo ra sự khác biệt.


1
Điều này không làm nổi bật sự khác biệt trong dòng. Nếu bạn có một hàng dài, thật đau lòng khi thấy sự khác biệt. wdiff, git diff --word-diff, vimgit, meld, kbdiff3, tkdiff đều làm điều này.
dùng2707671

1

Tôi đã có cùng một vấn đề và giải quyết nó với PHP Fine Diff , một công cụ trực tuyến cho phép bạn chỉ định mức độ chi tiết. Tôi biết về mặt kỹ thuật nó không phải là một công cụ * nix, nhưng tôi không thực sự muốn tải xuống một chương trình chỉ để thực hiện một mức độ khác nhau, một lần.


Một số người dùng không thể tải các tệp nhạy cảm hoặc lớn lên một công cụ trực tuyến ngẫu nhiên. Có rất nhiều công cụ thể hiện sự khác biệt ở cấp độ dòng mà không ảnh hưởng đến quyền riêng tư của bạn.
Dan Dascalescu

Vâng, có. Nhưng đối với các khác biệt không chứa thông tin nhạy cảm, các công cụ trực tuyến có thể là một giải pháp tốt.
trụ cột

Các công cụ tìm khác biệt trực tuyến cũng không hỗ trợ tích hợp dòng lệnh. Bạn không thể sử dụng chúng từ luồng kiểm soát phiên bản của bạn. Chúng cũng cồng kềnh hơn khi sử dụng (chọn tệp 1, chọn tệp 2, tải lên) và không thể thực hiện hợp nhất.
Dan Dascalescu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.