Linux sdiff command

Updated: 11/06/2021 by Computer Hope
sdiff command

On Unix-like operating systems, the sdiff command compares two files side-by-side, optionally merges them interactively, and outputs the results.

This page covers the GNU/Linux version of sdiff.

Description

sdiff performs a side-by-side comparison of the differences between FILE1 and FILE2, and optionally merges them (see the -o option, below).

If one of the FILEs is specified as a dash ("-"), sdiff reads from standard input.

Syntax

sdiff [OPTION]... FILE1 FILE2

Options

-o FILE, --output=FILE

Merge the files interactively, and send the output to FILE.

Specifying this option will begin the side-by-side comparison, and place you at a "%" prompt, asking you how to treat the differences. Press Enter at the prompt to view the merging options, which are as follows:

ed Edit then use both versions, each decorated with a header.
eb Edit then use both versions.
el or e1 Edit, then use the left version.
er or e2 Edit, then use the right version.
e Discard both versions, then edit a new one.
l or 1 Use the left version.
r or 2 Use the right version.
s Silently include common lines.
v Verbosely include common lines.
q Quit.
When merging is complete, the merged contents will be written to FILE.
-i, --ignore-case Treat uppercase and lowercase letters as if they are the same.
-E,
--ignore-tab-expansion
Ignore changes due to tab expansion (where tabs are expanded to blanks or spaces).
-b,
--ignore-space-change
Ignore changes in the amount of white space (spaces, tabs, etc).
-W, --ignore-all-space Ignore all white space.
-B, --ignore-blank-lines Ignore changes whose lines are all blank.
-I RE,
--ignore-matching-lines=RE
Ignore changes whose lines all match regular expression RE.
--strip-trailing-cr Strip trailing carriage return on input.
-a, --text Treat all files as text files.
-w NUM, --width=NUM Output at most NUM (default 130) print columns.
-l, --left-column Output only the left column of common lines.
-s, --suppress-common-lines Do not output common lines.
-t, --expand-tabs Expand tabs to spaces in output.
--tabsize=NUM Set tab stops at every NUM (default 8) print columns.
-d, --minimal Try hard to find a smaller set of changes.
-H, --speed-large-files Assume large files (which contain many scattered, small changes).
--diff-program=PROGRAM Use PROGRAM to compare files.
--help Display a help message and exit.
-v, --version Output version information and exit.

Displaying differences side-by-side

sdiff produces a side-by-side difference listing of the two files. The contents of the files are listed in two columns with a "gutter" between them. The gutter contains one of the following markers:

whitespace The corresponding lines are in common. That is, either the lines are identical, or the difference is ignored because of one of the --ignore options (see: handling white space differences, below).
| The corresponding lines differ, and they are either both complete or both incomplete.
< The files differ and only the first file contains the line.
> The files differ and only the second file contains the line.
( Only the first file contains the line, but the difference is ignored.
) Only the second file contains the line, but the difference is ignored.
\ The corresponding lines differ, and only the first line is incomplete.
/ The corresponding lines differ, and only the second line is incomplete.

Normally, an output line is incomplete if and only if the lines that it contains are incomplete. However, when an output line represents two differing lines, one might be incomplete while the other is not. Which means the output line is complete, but its the gutter is marked "\" if the first line is incomplete, "/" if the second line is.

Side by side format is sometimes easiest to read, but it has limitations. It generates much wider output than usual, and truncates the display of any lines that are too long to fit. Also, it relies on lining up output more heavily than usual, so its output looks particularly bad if you use varying width fonts, nonstandard tab stops, or nonprinting characters.

Handling white space differences

The --ignore-tab-expansion (-E) option ignores the distinction between tabs and spaces on input. A tab is considered to be equivalent to the number of spaces to the next tab stop.

The --ignore-trailing-space (-Z) option ignores white space at line end.

The --ignore-space-change (-b) option is stronger than -E and -Z combined. It ignores white space at line end, and considers all other sequences of one or more white space characters within a line to be equivalent. With this option, sdiff considers the following two lines to be equivalent, where ‘$’ denotes the line end:

Here lyeth  muche rychnesse  in lytell space.   -- John Heywood$
Here lyeth muche rychnesse in lytell space. -- John Heywood   $

The --ignore-all-space (-w) option is stronger still. It ignores differences even if one line has white space where the other line has none. White space characters include tab, vertical tab, form feed, carriage return, and space; some locales may define additional characters to be white space. With this option, sdiff considers the following two lines to be equivalent, where ‘$’ denotes the line end and ‘^M’ denotes a carriage return:

Here lyeth  muche  rychnesse in lytell space.--  John Heywood$
  He relyeth much erychnes  seinly tells pace.  --John Heywood   ^M$

For other programs the newline character is considered a white space character, but sdiff is a line-oriented program and a newline character always ends a line. Hence the -w or --ignore-all-space option does not ignore newline-related changes; it ignores only other white space changes.

Merging interactively

If you specify an output file using the -o option, sdiff displays differences side-by-side in groups of differing lines, and give you a prompt ("%") where you can choose, case by case, how to handle the differences to create a merged output file.

For instance, let's say we have two files, cats.c and cats2.c, shown here side by side:

cats.c:                                              cats2.c:
/*                                                │ /*
cats, a program.                                  │ "cats", a computer program.
Tells you if your cat is alive or dead.           │ Tells you if your cat is alive or dead.
by E. Schrödinger.                                │ by E. Schrödinger.
*/                                                │ */
                                                  │ 
#include <stdio.h>                                │ #include <stdio.h>
#include <stdlib.h>                               │ #include <stdlib.h>
#include <time.h>                                 │ #include <time.h>
                                                  │ 
int main () {                                     │ int main () {
                                                  │ 
    double  numCats;                              │     /* seed pseudorandomizer */
    double  chance = (double)rand();              │     srand( time( NULL ) );
                                                  │ 
    chance = chance / (double)RAND_MAX;           │     double  numCats;
                                                  │     double  chance = (double)rand();
    if ( chance > 0.5 ) {                         │ 
            printf("Felix is alive.\n");          │     chance = chance / 1;
    } else if ( chance < 0.5 ) {                  │ 
            printf("Felix is not alive.\n");      │     if ( chance > 0.5 ) {
    } else {                                      │             printf("My cat is alive.\n");
            printf("Felix is alive and dead.\n"); │     } else if ( chance < 0.5 ) {
    }                                             │             printf("My cat is dead.\n");
}                                                 │     } else {
                                                  │             printf("My cat might be alive.\n");
                                                  │     }
                                                  │ }

There are differences in these two files, and we have to decide which ones to keep. Let's run sdiff on the two files, specifying an output file so sdiff knows we also want to perform a merge:

sdiff -o merged_cats.c cats.c cats2.c

sdiff outputs to the screen:

/*                            /*
cats, a program.              |     "cats", a computer program.

Here, we see the first two lines of our file — the second line has differences, so sdiff stops there, and gives us a prompt ("%"). The vertical bar ("|") is in what's called "the gutter" — the space separating the two lines — and it means that these two lines "line up", that is, their position in their respective files corresponds. If we press Enter at the prompt, sdiff gives us a brief command listing:

ed:       Edit then use both versions, each decorated with a header.
eb:       Edit then use both versions.
el or e1: Edit then use the left version.
er or e2: Edit then use the right version.
e:        Discard both versions then edit a new one.
l or 1:   Use the left version.
r or 2:   Use the right version.
s:        Silently include common lines.
v:        Verbosely include common lines.
q:        Quit.

All of the options which begin with e (ed, eb, etc.) open an editor (ed or vi, by default) and allow us to manually edit the lines to resolve the differences. For instance, if we enter the command ed at the % prompt:

%ed

...we see the following in our editor:

--- cats.c 2
cats, a program.
+++ cats2.c 2
"cats", a computer program.

This is a temporary file showing our two differing lines, "decorated with a header": the line from file 1 has three dashes ("---"), the file name, and the line number; the line from file 2 has three plus signs ("+++"), the file name, and the line number. The headers should be deleted, and the two remaining lines should be edited down to one line which represents your manual merge. When you write the temporary file and quit the editor, sdiff resolves the diff with whatever you saved (including the headers if you don't delete them, so make sure you do). If you don't write any changes, sdiff uses the headers and the unchanged lines as the resolution, so make sure you make an edit and write the changes.

Alternatively, we could have chosen l (lowercase L) or r to choose the line from file 1 or file 2, respectively. Let's say we want the line from file 2, so we'll type r.

%r

sdiff proceeds through the file, asking us to resolve differences every time it finds any:

Tells you if your cat is alive or dead.         Tells you if your cat is alive or dead.
by E. Schrödinger.                              by E. Schrödinger.
*/                                              */
#include <stdio.h>                              #include <stdio.h>
#include <stdlib.h>                             #include <stdlib.h>
#include <time.h>                               #include <time.h>
int main () {                                         int main () {
                                               >         /* seed pseudorandomizer */
                                               >         srand( time( NULL ) );
                                               >

Here, the three ">" symbols in the gutter, before the last three lines on the right, tell us that these lines appear in file 2 but not file 1. If we enter l (lowercase L), these lines are deleted from this block of lines; if we enter r, they are kept. Let's keep them:

%r

The next set is then displayed:

    double  numCats;                                    double  numCats;
    double  chance = (double)rand();                    double  chance = (double)rand();
    chance = chance / (double)RAND_MAX;        |        chance = chance / 1;

The vertical bar in the gutter on the last line tells us that these two versions of a corresponding line differ and must be resolved. On closer analysis, the one on the left, in file 1, is the version of the line we want to keep, so we'll type l at the prompt:

%l

The next set is then displayed:

    if ( chance > 0.5 ) {                              if ( chance > 0.5 ) {
        printf("Felix is alive.\n");           |           printf("My cat is alive.\n");

Here it's a matter of preference. Let's keep the version on the right:

%r

And so on, through the end of the file:

    } else if ( chance < 0.5 ) {                    } else if ( chance < 0.5 ) {
        printf("Felix is not alive.\n");       |        printf("My cat is dead.\n");
%r
    } else {                                        } else {
        printf("Felix is alive and dead.\n");  |        printf("My cat might be alive.\n");

There are no more differences, so sdiff prints the remaining lines of the file, and returns us to the shell command prompt.

Let's look at our merged file:

cat merged_cats.c
/*
"cats", a computer program.
Tells you if your cat is alive or dead.
by E. Schrödinger.
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main () {
    /* seed pseudorandomizer */
    srand( time( NULL ) );
    double  numCats;
    double  chance = (double)rand();
    chance = chance / (double)RAND_MAX;
    if ( chance > 0.5 ) {
            printf("My cat is alive.\n");
    } else if ( chance < 0.5 ) {
            printf("My cat is dead.\n");
    } else {
            printf("My cat might be alive.\n");
    }
}

As you can see, our choices were incorporated into the merged file, and the versions we discarded were left out.

Environment variables

The two most relevant environment variables which affect sdiff (other than locale settings such as LC_ALL) are the EDITOR and VISUAL variables. These specify what editor, and what "visual" editor, you want to use by default when editing a file. These variables should be set to the full path of your favorite editor, for instance /usr/bin/vim for vim. If you're unsure where vim is located, try the which command:

which vim
/usr/bin/vim

In bash, set the variable and export it as follows:

EDITOR=/usr/bin/vim; export EDITOR

sdiff now uses the value of this variable when it launches an editor during an interactive merge.

If neither EDITOR nor VISUAL are defined, sdiff defaults to ed or vi (probably ed).

If both EDITOR and VISUAL are defined, VISUAL overrides EDITOR.

Examples

sdiff file1.txt file2.txt

Compares the files file1.txt and file2.txt side-by-side, displaying differences on standard output.

sdiff - < file1.txt file2.txt

In this command configuration, sdiff compares the text it receives from standard input, which is the contents of file1.txt and file2.txt.

Note

sdiff cannot perform an interactive merge when its source material comes from stdin.

sdiff -o output.txt file1.txt file2.txt

Performs an interactive merge of file1.txt and file2.txt. Differences are displayed in blocks, with context, from the first line of the files through the last. sdiff prompts you every time it needs you to decide what action to take to resolve differences. Press Enter at the % prompt for a cheat sheet of possible commands, or refer to the command descriptions above in this page for more information.

When the end of the is reached, sdiff writes a merged file, based on your decisions, to the specified file name output.txt.

diff — Identify the differences between two files.
ed — A simple text editor.
ex — Line-editor mode of the vi text editor.
vi — Text editor based on the visual mode of ex.
vim — An advanced version of vi.