The problem can be solved by filtering the output of diff
. This example works for me (though the placement and size of the gutter between left/right sides of the diff output are likely to be a detail that differs between implementations):
#!/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;
}
}
'
You cannot add line numbers before diff
, because if there are insertions or deletions, the line numbers starting at that point will not match, making the differences not useful. My script computes the line numbers for the left/right sides of the difference in the awk script:
- It first decides how wide to make the diff, based on the width of the terminal.
- There is (in GNU diff 3.2 which I tested) a gutter (unused space) in the middle of the side-by-side differences. Starting with an 80-column terminal, I determined a way to compute the position of the gutter.
- After initializing, the script extracts from each line (in
awk
, this is $0
) the left (textL
) and right (textR
) strings, and tests if they are empty (which would happen if there were an insert/delete).
- If the left/right lines are different, the script reconstructs the
diff
output, but adding the line-numbers.
Given this on the left
1
2
3
4
This is line A
6
This is line C
123456789.123456789.123456789.123456789.123456789.
yyy
and this on the right
1
2
3
4
This is line B
6
This is line D
abcdefghi.abcdefghi.abcdefghi.abcdefghi.abcdefghi.
xxx
(10 lines on the left, 9 on the right), this script produces
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 <
nl
to add lines numbers to your input file and then pass ontodiff
.. and whats with snide remarks in question?diff
will report even whitespace mismatches.. and either way, seeman diff
and use options to ignore white-space mismatches being reported in output