Weekly Command: comparing files line by line with diff
Tags: weeklycommand, xnix
Published: 2018-06-01 11:44:37

---
title: Weekly Command: comparing files line by line with diff
published: true
tags: weekly-command,xnix
canonical_url: https://monades.roperzh.com/weekly-command-comparing-files-line-by-line-with-diff/
---


## The basics

<div class="highlight">
  <pre><strong>diff</strong> [<i>option</i>] [<i>files</i>]</pre>
</div>

`diff` outputs the differences between two files, line by line. For files that are identical it produces no output, for binary files only reports if they are different or not.

The set of differences produced by `diff` is often called a _diff_ or _patch_, and this output can be used later on by the [`patch`][patch-man] command to change other files.

## Play by play

Before digging into the examples, let's define two files that will help us to illustrate some concepts.

To keep the conceptual overhead as low as possible, the files are `with-text.js` and `without-text.js` to represent if the `text` variable is present or not.

File `with-text.js`:

```js
function example (text) {
  console.log("====")
  console.log(text)
}
```

File `without-text.js`:

```js
function something () {
  console.log("====")
}
```

###  Default output

By default, `diff` outputs a list of all the lines that are different between the files, one after the other, alongside with useful information about what changed. A change can be:

- An addition, represented by the letter `a`.
- A deletion, represented by the letter `d`.
- A change, represented by the letter `c`.

For every line in which `diff` finds a change, it outputs:

- What type of change is (`a/c/d`)
- What is the line number affected in each file
- The content of the lines affected

In a more concrete example, if you run:

```text
$ diff with-text.js without-text.js

1c1
< function example (text) {
---
> function something () {
3d2
<   console.log(text)
```

You get:

- `1c1` indicating that there's a `c`hange in line `1` of both files.
- `< function example (text) {` indicating how the line looks in `with-text.js`.
- `> function something () {` indicating how the line looks in `without-text.js`.

Are you able to deduce what the rest of the lines are expressing in the output?

###  Side by side comparison

Apart from the default output format, you can specify the `--side-by-side` (short `-y`) to produce a side-by-side view of what changed.

This format is more visual and can be easier to understand at first sight, for example:

```text
$ diff with-text.js without-text.js --side-by-side

function example (text) {             | function something () {
  console.log("====")                     console.log("====")
  console.log(text)                   <
}                                       }
```

###  Working with directories

A very powerful feature of `diff` is the ability to work with directories. It's important to note that actual contents of directories are never compared as if they were a file, instead `diff` uses the following rules:

- If one file is a directory and the other is not, `diff` compares the file in the directory whose name is that of the non-directory.
- If two file names are given and both are directories, `diff` compares corresponding files in both directories, in alphabetical order.

###  Colorised output

Since version 3.4 ([launched][diff-version-3-4] around August of 2016), `diff` supports the `--color` flag print colorised output in the terminal.

### Reading standard input

If you provide `-` as a file name, `diff` will use it for text read from the standard input. As a special case, `diff - -` compares a copy of standard input to itself.

### Omitting differences

`diff` also provides ways to suppress differences between files that may not be important to you, common examples of this are changes in the amount of white space between words or lines.


| Flag                                  | Description                                  |
| ------------------------------------- | -------------------------------------------- |
| \-i \-\-ignore\-case                  | Ignore case differences in file contents.    |
| \-\-ignore\-file\-name\-case          | Ignore case when comparing file names.       |
| \-\-no\-ignore\-file\-name\-case      | Consider case when comparing file names.     |
| \-E \-\-ignore\-tab\-expansion        | Ignore changes due to tab expansion.         |
| \-b \-\-ignore\-space\-change         | Ignore changes in the amount of white space. |
| \-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 RE.     |

## Using the right tool for the job

While `diff` awesome, it's not always the right tool for the job, here are some better fits for different scenarios:

- The `diff3` command can be useful to show differences among _three_ files.
- For binary files, `cmp` reports the differences between two files byte by byte, instead of line by line.
- If you are looking only for visual diffing without the patching, `vim -d` and `git diff` do a good job.

[diff-version-3-4]: https://savannah.gnu.org/forum/forum.php?forum_id=8639
[patch-man]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/patch.html