різниться в межах рядка


113

У мене є кілька відвалів sql, які я дивлюся на відмінності між. diffОчевидно, я можу показати мені різницю між двома рядками, але я запускаю гайки, намагаючись знайти, які значення у довгому списку розділених комами значень насправді є тими, що призводять до того, що лінії будуть різними.

Який інструмент можна використовувати, щоб вказати точні відмінності символів між двома рядками в певних файлах?


Відповіді:


93

Існує wdiff , слово для цього відрізняється .

На робочому столі meld може виділити відмінності в межах рядка для вас.


8
Кольоровий wdiff:wdiff -w "$(tput bold;tput setaf 1)" -x "$(tput sgr0)" -y "$(tput bold;tput setaf 2)" -z "$(tput sgr0)" file1 file2
— l0b0

47
Для кольору встановіть colordiff , а потім виконайте:wdiff a b | colordiff
— philfreo

Meld насправді дуже повільний (хвилин), показуючи внутрішньолінійні відмінності між файлами на основі рядків.
— Дан Даскалеску

Також є dwdiffінструмент, який в основному сумісний з, wdiffале також підтримує кольоровий вихід і, можливо, деякі інші функції. І він доступніший у деяких дистрибутивах Linux, таких як Arch.
— MarSoft

4
wdiff -n a b | colordiff, радить man colordiff.
— Каміль Ґудсейне

25

Ще один метод з використанням git-diff:

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

grep -v, якщо не цікавляться позиціями розріз.


2
Саме таку поведінку я намагався імітувати - не зрозумів, що можу використовувати git-diff без індексування одного з файлів.
— спінуп

1
- word-diff - ключовий варіант тут. Дякую!
— user2707671

1
--no-index потрібен лише у тому випадку, якщо ви перебуваєте в робочій директорії git, а також foo та bar.
— хн.

22

Я використовував vimdiffдля цього.

Ось скріншот (не мій), на якому показано незначні відмінності в одному-двох символах, які досить добре виділяються. Короткий підручник теж .


У моєму випадку не вдалося помітити різницю, тому відкрилися файли в gvim -d f1 f2, окремі довгі рядки були виділені як різні, однак фактична різниця була додатково виділена червоним кольором
— zzapper

Я використовую vim назавжди, але поняття про vimdiff не мав!
— mitchus

І існує diffchar.vim для рівня символів.

2
Наскільки я люблю vim та vimdiff, алгоритм vimdiff для виділення відмінностей у рядку є досить простим. Здається, просто викреслити загальний префікс і суфікс, і виділити все між собою як різні. Це працює, якщо всі змінені символи згруповані разом, але якщо вони рознесені, це не спрацює. Це також страшно для текстового перекладеного тексту.
— Лоранс Гонсалвс

Для довгих ліній, як в ОП vimdiff -c 'set wrap' -c 'wincmd w' -c 'set wrap' a b, пропонує stackoverflow.com/a/45333535/2097284 .
— Каміль Ґудсейне

6

Ось метод ".. волоса собаки, яка тебе кусав" ... довів
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 
║  ║   ^ ║      ║     ║    ║          ║     ^

Ось сценарій .. Вам просто потрібно викреслити пари ліній якимось чином (я раніше сьогодні використовував диференційований раз (двічі?), Тому я не знаю його безлічі варіантів, і сортування варіантів для цього сценарію мені вистачило на один день :) .. Я думаю, що він повинен бути досить простим, але мені належить перерва на каву ....

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

wdiffнасправді дуже старий метод порівняння файлів слово за словом. Він працював шляхом переформатування файлів, а потім за допомогою diffзнаходження відмінностей та повернення їх знову. Я сам запропонував додати контекст, щоб замість того, щоб порівнювати слово за словом, він це робив із кожним словом, оточеним іншими «контекстними» словами. Це дозволяє розрізнити синхронізувати себе на звичайних уривках у файлах набагато краще, особливо коли файли здебільшого відрізняються лише кількома блоками загальних слів. Наприклад, при порівнянні тексту для плагіату чи повторного використання.

dwdiffпізніше був створений з wdiff. Але dwdiff використовує цю функцію переформатування тексту для хорошого ефекту в dwfilter. Це чудова розробка - це означає, що ви можете переформатувати один текст, щоб він відповідав іншому, а потім порівнювати їх за допомогою будь-якого рядкового графічного дисплея. Наприклад, використовуючи його з "дифузним" графічним розд ...

dwfilter file1 file2 diffuse -w

Це переформатує file1у формат file2і дає це diffuseдля візуального порівняння. file2є немодифікованим, тож ви можете редагувати та об’єднувати в ньому різниці слів безпосередньо diffuse. Якщо ви хочете відредагувати file1, ви можете додати -rдо зворотнього ходу, який файл буде переформатований. Спробуйте, і ви побачите, що це надзвичайно потужно!

Моя перевага для графічного розбіжності (показаного вище) - diffuseце те, що він відчуває себе набагато чистішим та кориснішим. Крім того, це автономна програма python, що означає, що її легко встановлювати та розповсюджувати в інших системах UNIX.

Інші графічні відмінності, здається, мають багато залежностей, але їх також можна використовувати (ви обираєте). До них належать kdiff3або xxdiff.


4

Використання @ Peter.O в розчині в якості основи я переписав його , щоб зробити ряд змін.

введіть тут опис зображення

  • Він друкує кожен рядок лише один раз, використовуючи колір, щоб показати вам відмінності.
  • Він не записує жодних тимчасових файлів, замість цього виконуючи все.
  • Ви можете надати дві назви файлів, і вони порівнюватимуть відповідні рядки у кожному файлі. ./hairOfTheDiff.sh file1.txt file2.txt
  • В іншому випадку, якщо ви використовуєте оригінальний формат (один файл із кожним другим рядком, який потрібно порівнювати з попереднім), тепер ви можете просто передати його в дію, жоден файл не повинен існувати для читання. Погляньте на demoджерело; це може відкрити двері для фантазійних трубопроводів, щоб також не потрібні файли для двох окремих входів, використовуючи pasteдекілька файлових дескрипторів.

Ніяка підсвітка означає, що персонаж був у обох рядках, підсвічування означає, що він був у першому, а червоний означає, що він був у другому.

Кольори можна змінювати за допомогою змінних у верхній частині сценарію, і ви навіть можете повністю відмовитися від кольорів, використовуючи звичайні символи для вираження відмінностей.

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

Ось простий однолінійний:

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

Ідея полягає в заміні коми (або будь-який роздільник, який ви хочете використовувати) на використання нових рядків sed. diffпотім дбає про інше.


2
  • xxdiff: Іншим інструментом є xxdiff (GUI), який потрібно спочатку встановити.
  • електронна таблиця: для даних бази даних .csvлегко створюється електронна таблиця , а формула (A7==K7) ? "" : "diff"або подібне вставляється та копіюється.

1
xxdiff виглядає як 80-ті. Meld виглядає набагато краще, але це дуже повільно для CSV-подібних файлів. Я виявив, що Diffuse є найшвидшим інструментом для розробки Linux.
— Дан Даскалеску

@DanDascalescu: Інструмент, який виконує роботу, виглядає завжди чудово, незалежно від того, скільки років він виглядає. Інший, який я використовував періодично, але не встановлений, щоб перевірити його довгими даними стовпців, це tkdiff .
— користувач невідомий

Чи відображає xxdiff переміщені лінії ? Або він просто показує пропущений рядок в одному файлі та доданий один в іншому? (Я спробував створити xxdiff, але qmake не вдався, і я бачу, що вони не намагаються опублікувати пакет Debian).
— Дан Даскалеску

@DanDascalescu: Сьогодні у мене встановлено лише tkdiff.
— користувач невідомий

1

У командному рядку я переконуюсь, що я додаю розумні нові рядки перед порівнянням файлів. Ви можете використовувати sed, awk, perl або що-небудь по-справжньому, щоб додати розриви рядків якимось систематичним способом - хоч не забудьте додати занадто багато.

Але я вважаю, що найкраще використовувати vim, оскільки він підкреслює відмінності в словах. vim добре, якщо відмінностей не дуже багато, а відмінності прості.


Хоча насправді не є відповіддю на питання, ця методика є досить ефективною для того, щоб дізнатися про невеликі відмінності довгих рядків.
— jknappen

1

kdiff3 стає стандартним переглядачем графічного інтерфейсу для Linux. Це схоже на xxdiff , але я думаю, що kdiff3 краще. Це робить багато речей, зокрема ваш запит показати "точні відмінності символів між двома рядками в певних файлах".


KDiff3 надзвичайно повільний, щоб виділити вбудовані відмінності у файлах CSV. Я б не рекомендував це.
— Дан Даскалеску

1

Якщо я правильно читаю ваше запитання, я використовую diff -yдля такого роду речі.

Це робить порівняння бічного порівняння набагато простішим, щоб знайти, які лінії кидають відмінності.


1
Це не підкреслює різницю в межах рядка. Якщо у вас довга черга, різко бачити різницю. wdiff, git diff --word-diff, vimgit, meld, kbdiff3, tkdiff все це роблять.
— user2707671

1

У мене була та сама проблема, і я вирішив її за допомогою PHP Fine Diff , онлайн-інструменту, який дозволяє вказати деталізацію. Я знаю, що це технічно не інструмент * nix, але я не дуже хотів завантажувати програму просто для одноразового, різного рівня символів.


Деякі користувачі не можуть завантажувати чутливі чи великі файли у випадковий онлайн-інструмент. Є безліч інструментів, які показують відмінності на рівні лінії, не порушуючи конфіденційність.
— Дан Даскалеску

Так, є. Але для відмінників, які не містять конфіденційну інформацію, онлайн-інструменти можуть бути хорошим рішенням.
— pillravi

Інтернет-інструменти різниці також не підтримують інтеграцію командного рядка. Ви не можете використовувати їх у потоці управління версіями. Вони також набагато громіздкіші у використанні (виберіть файл 1, виберіть файл 2, завантажте) і не можуть зробити об'єднання.
— Дан Даскалеску
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.