
Mein Szenario ist folgendes:
diff
Generieren Sie zunächst zwei Dateien nebeneinander mit:
diff -y --supress-common-lines file1.txt file2.txt > DiffResult.txt
Ausgabe von DiffResult.txt
:
file1.txt file2.txt
This is line A | This is line B
This is line C | This is line D
Nehmen wir nun die Zeile
This is line A
Und
This is line B
befinden sich in Zeile 5 von file1.txt
bzw. file2.txt
Dann sollte ich in der Lage sein, die entsprechende Zeilennummer wie folgt zuzuordnen:
Gewünschte Ausgabe von DiffResult.txt
:
file1.txt file2.txt
5 This is line A | 5 This is line B
7 This is line C | 7 This is line D
Der Grund, warum ich diesen Ansatz wähle, liegt darin, dass, wenn ich die Zeilennummern vor generiere diff
, sogar bei einer kleinen Änderung der Leerzeichen diff
ein Unterschied angezeigt würde, da den Zeilennummern die Zeilennummern zugeordnet sind.
Hat jemand gute Ideen? Ich glaube, das ist die schwierigste Frage, die jemals bei StackExchange gestellt wurde :D
Antwort1
Das Problem kann durch Filtern der Ausgabe von gelöst werden diff
. Dieses Beispiel funktioniert bei mir (obwohl die Platzierung und Größe des Randes zwischen den linken und rechten Seiten der Diff-Ausgabe wahrscheinlich ein Detail ist, das sich zwischen den Implementierungen unterscheidet):
#!/bin/sh
# $Id: diff-two-column,v 1.2 2016/09/26 20:38:32 tom Exp $
# see http://unix.stackexchange.com/questions/312025/how-to-associate-line-number-from-a-file-to-the-side-by-side-diff-output-result
usage() {
cat >&2 <<EOF
usage: $0 file1 file2
EOF
exit 1
}
[ $# = 2 ] || usage
[ -f "$1" ] || usage
[ -f "$2" ] || usage
width=${COLUMNS:-80}
check=$(stty size|cut -d' ' -f2)
[ -n "$check" ] && width=$check
diff -W $width -y "$1" "$2" | \
expand | \
awk -v width=$width '
BEGIN {
L=0;
R=0;
gutter = width / 2;
half = gutter - 2;
}
{
textL = substr($0, 1, half - 1);
sub("[ ]+$", "", textL); # trim trailing blanks
# The script relies on correctly extracting textM, the gutter:
# if lines differ, textM is " ! "
# if line inserted, textM is " > "
# if line deleted, textM is " < "
# if lines unchanged, textM is " "
textM = substr($0, gutter - 2, 3);
textR = ( length($0) > gutter ) ? substr($0, gutter+1, half) : "";
if ( textM != " > " ) {
L++;
}
if ( textM != " < " ) {
R++;
}
if ( textL != textR ) {
# printf "SHOW %s\n", $0;
# printf "gap \"%s\"\n", textM;
# printf "<<< \"%s\"\n", textL;
# printf ">>> \"%s\"\n", textR;
if ( textL == "" ) {
printf "%5s %-*s %-3s %5d %s\n",
" ", half, textL,
textM,
R, textR;
} else if ( textR == "" ) {
printf "%5d %-*s %-3s %5s %s\n",
L, half, textL,
textM,
" ", textR;
} else {
printf "%5d %-*s %-3s %5d %s\n",
L, half, textL,
textM,
R, textR;
}
} else {
# printf "SKIP %s\n", $0;
}
}
'
Sie können keine Zeilennummern hinzufügenVor diff
, denn wenn Einfügungen oder Löschungen vorhanden sind, stimmen die Zeilennummern ab diesem Punkt nicht überein, wodurch die Unterschiede nicht nützlich sind. Mein Skript berechnet die Zeilennummern für die linke/rechte Seite des Unterschieds im awk-Skript:
- Zunächst wird basierend auf der Breite des Terminals entschieden, wie breit der Diff sein soll.
- Es gibt (in GNU diff 3.2, das ich getestet habe) eineRinne(ungenutzter Platz) in der Mitte der nebeneinander liegenden Unterschiede. Ausgehend von einem 80-Spalten-Terminal habe ich eine Möglichkeit gefunden, die Position des Randes zu berechnen.
- Nach der Initialisierung extrahiert das Skript aus jeder Zeile (in
awk
ist dies$0
) die linken (textL
) und rechten (textR
) Zeichenfolgen und prüft, ob sie leer sind (was bei einem Einfügen/Löschen passieren würde). - Wenn die linken und rechten Zeilen unterschiedlich sind, rekonstruiert das Skript die
diff
Ausgabe, fügt jedoch die Zeilennummern hinzu.
Angesichts dessen auf der linken
1
2
3
4
This is line A
6
This is line C
123456789.123456789.123456789.123456789.123456789.
yyy
und das hier rechts
1
2
3
4
This is line B
6
This is line D
abcdefghi.abcdefghi.abcdefghi.abcdefghi.abcdefghi.
xxx
(10 Zeilen links, 9 rechts), dieses Skript erzeugt
5 This is line A | 5 This is line B
7 This is line C | 7 This is line D
8 123456789.123456789.123456789.1234567 | 8 abcdefghi.abcdefghi.abcdefghi.abcdefg
| 9 xxx
10 yyy <