83

I wanted to format the Unix files conditionally, I am currently working on diff command and wanted to know if it is possible to format the text of the diff command output.

Example:

Matched values should be displayed in green.
Unmatched values should be displayed in red.

Suppose I have two files file1 and file2 and my command is diff file1 file2.

Now I wanted that suppose output contain 5 mismatch then those mismatch should be displayed in Red color. How to achieve this using unix?

In short "Change color to red for the output of diff command for values which mismatch"

2
  • 2
    Possible duplicate of this
    – FloHimself
    Apr 16, 2015 at 10:18
  • The terms "match" and "mismach" are a bit confusing. Anyway, there's the --color option now in diff 3.4 and later. Aug 10, 2017 at 2:48

15 Answers 15

100

diff --color option was added to GNU diffutils 3.4 (2016-08-08)

This is the default diff implementation on most distros, which will soon be getting it.

Ubuntu 18.04 has diffutils 3.6 and therefore has it.

On 3.5 it looks like this:

enter image description here

Tested:

diff --color -u \
  <(seq 6 | sed 's/$/ a/') \
  <(seq 8 | grep -Ev '^(2|3)$' | sed 's/$/ a/')

Apparently added in commit c0fa19fe92da71404f809aafb5f51cfd99b1bee2 (Mar 2015).

Word-level diff

Like diff-highlight. Not possible it seems, feature request: https://lists.gnu.org/archive/html/diffutils-devel/2017-01/msg00001.html

Related threads:

ydiff does it though, see below.

ydiff side-by-side word level diff

https://github.com/ymattw/ydiff

Is this Nirvana?

python3 -m pip install --user ydiff
diff -u a b | ydiff -s

Outcome:

enter image description here

If the lines are too narrow (default 80 columns), fit to screen with:

diff -u a b | ydiff -w 0 -s

Contents of the test files:

a

1
2
3
4
5 the original line the original line the original line the original line
6
7
8
9
10
11
12
13
14
15 the original line the original line the original line the original line
16
17
18
19
20

b

1
2
3
4
5 the original line teh original line the original line the original line
6
7
8
9
10
11
12
13
14
15 the original line the original line the original line the origlnal line
16
17
18
19
20

ydiff Git integration

ydiff integrates with Git without any configuration required.

From inside a git repository, instead of git diff, you can do just:

ydiff -s

and instead of git log:

ydiff -ls

See also: https://stackoverflow.com/questions/7669963/how-can-i-get-a-side-by-side-diff-when-i-do-git-diff/14649328#14649328

Tested on Ubuntu 16.04, git 2.18.0, ydiff 1.1.

10
  • 1
    Excellent! To enable this by default: alias diff='diff --color=auto'
    – Tom Hale
    Feb 20, 2017 at 12:26
  • 2
    Here is the documentation.
    – Alexey
    Apr 12, 2017 at 14:12
  • does not work on Centos 7 May 19, 2020 at 0:00
  • 1
    Does anyone know why the color gets lost if I pipe to more? Or how to fix this behavior? (or a better way to slowly scroll through the diff output?)
    – Tyler R.
    Jan 4, 2022 at 16:31
  • 1
    @TylerR. see: superuser.com/questions/117841/… Jan 4, 2022 at 17:14
28

If you have access to GNU diff you can use its --X-group-format options to get that effect without any additional tools:

diff --old-group-format=$'\e[0;31m%<\e[0m' \
     --new-group-format=$'\e[0;31m%>\e[0m' \
     --unchanged-group-format=$'\e[0;32m%=\e[0m' \
     file1 file2

That uses ANSI colour escape codes to get red and green, with ANSI-C quoting in the shell to access the \e escapes.

--old-group-format and --new-group-format identify non-matching lines and insert them between red and colour reset codes using %< and %>, while --unchanged-group-format inserts matching lines between green and reset codes.

You can also use --old-line-format (etc), at the expense of redundant colour escapes on every line: --old-line-format=$'\e[0;31m%L\e[0m'.

10
  • when I run it gives diff: 0653-821 illegal option -- - diff: 0653-821 illegal option -- o diff: 0653-821 illegal option -- d diff: 0653-821 illegal option -- - diff: 0653-821 illegal option -- g diff: 0653-821 illegal option -- o like errors.
    – Aman
    Apr 16, 2015 at 11:26
  • Hormer when i am running your commands as by one line at a time it is giving new line no output -bash-4.2$ --new-group-format=$'\e[0;31m%>\e[0m' \ >
    – Aman
    Apr 16, 2015 at 11:32
  • May I configure that by default? Jul 6, 2018 at 11:22
  • 1
    @EugenKonkov You could set up an alias or function in your shell to run that for diff. Jul 6, 2018 at 19:35
  • 1
    @Ansa211 That is what the question asked for, rather than traditional colordiff-style output, but you can shift the green escape (32) into --new-group-format and drop the unchanged entry entirely to get that (though diff --color or colordiff is almost certainly better now if you don't have those very specific requirements - and it uses line-by-line colouring so difff --color ... | less -R doesn't break it). Jan 25, 2021 at 21:15
13

Try colordiff file1 file2

Availability of colordiff with your Linux/BSD distribution

Those running Debian or Ubuntu (or any of their derivatives) can probably just use "apt-get install colordiff" to download and install; colordiff is also packaged for a number of other Linux, UNIX and BSD distributions and operating systems.

(Quote from http://www.colordiff.org/)

1
  • 1
    Perfect. For me, diff --color=auto was only colourising line markers and the first line of each +/- section. Piping to less -SR makes for easy browsing.
    – Walf
    Oct 18, 2018 at 1:03
10

if you have vim installed, you can do diff file1 file2 | vim -

Vim will recognise diff format and give it proper coloring. The dash at the end is to let vim accept input from diff command.

2
  • 2
    'view' (the read-only shortcut to vim) is better suited for this purpose. Oct 29, 2019 at 8:53
  • this completely wrecked my terminal May 19, 2020 at 0:02
7

Coloured, word-level diff ouput

Here's what you can do with the the below script and diff-highlight:

Coloured diff screenshot

#!/bin/sh -eu

# Use diff-highlight to show word-level differences

diff -U3 --minimal "$@" |
  sed 's/^-/\x1b[1;31m-/;s/^+/\x1b[1;32m+/;s/^@/\x1b[1;34m@/;s/$/\x1b[0m/' |
  diff-highlight

(Credit to @retracile's answer for the sed highlighting)

2
  • 1
    Actually, diff-highlight does not do a word-level output. It just detects a common prefix and a common suffix on a changed line. For instance, if several words are changed, it will highlight everything from the first changed word to the last changed word. Moreover, this is effective only when only one line is changed between unchanged lines. In GNU Emacs, diff-mode does much better.
    – vinc17
    Mar 11, 2022 at 23:32
  • Installation: pip3 install --user diff-highlight May 2, 2023 at 17:29
4

Character-level color diff: Install ccdiff

ccdiff -r /usr/share/dict/words /tmp/new-dict

Output of ccdiff

2
  • That's the best answer so far. It's not C native, but does the job.
    – Smeterlink
    May 22, 2020 at 23:09
  • ccdiff seems to work well as a diff program, but unfortunately, it cannot color an existing diff (such as a patch).
    – vinc17
    Mar 11, 2022 at 23:37
3

To change diff's color palette use the --palette option (diff version 3.4 and higher):

diff --color=always --palette='ad=1;3;38;5;154:de=1;3;38;5;9' file1 file2

Here ad and de define the color of added and deleted text respectively. For a detailed description of diff options see man diff or info diff.

2
  • 1
    This is extremely flexible. It's nice to know that I can use whatever palette I want. Thanks. Jun 2, 2020 at 20:35
  • +1 I was searching for a --palette example, thanks! Sep 11, 2023 at 8:41
3

You could use :

  1. diff --color=auto file1 file2

  2. colordiff file1 file2

  3. git diff file1 file2 which is my favorite method

I currently use git diff or pipe it's output with colordiff :

diff() { git diff --no-index "$1" "$2" | colordiff; }

5
  • 1
    I like git diff --no-index too but I think files need to be seekable. (At least, doesn't work with bash process substitution for me)
    – Karl
    Aug 7, 2018 at 7:06
  • @Karl Figure that part out yourself, maybe there is a Terminal setting that does it (or) some other way to make it seekable. I've been using git diff from a long time and the file is seekable for me, otherwise there'd be no use of me doing it right.
    – himanshuxd
    Aug 7, 2018 at 17:26
  • 2
    Perhaps I wasn't clear very clear. As a (silly) example, this works for me diff --color <(ls | head -n+3) <(ls | tail -n +5) but not with git diff. Admittedly, not a common case or too hard to work around.
    – Karl
    Aug 8, 2018 at 2:11
  • git diff --no-index already colorizes the output, why on earth do you pass the output to colordiff? If the output has no color then you have wrong config, use git config color.diff auto to fix it
    – phuclv
    Jan 25, 2023 at 3:25
  • @phuclv at the time which is 2018, I think whatever terminal I was using was not coloring it with git diff itself or the color scheme might have been weird without the colordiff pipe.
    – himanshuxd
    Nov 22, 2023 at 21:10
2

This script uses the standard pre-version 3.4 diff (it should work with any version of diff) and colorizes the output without changing the output format in any way. It works with the latest version of RHEL (version 7.5) which has GNU diff version 3.3. Just put it in your ~/bin directory or anywhere else in your path (I suggest calling it "cdiff").

#!/bin/bash
file1color="$(tput setaf 1)"
file2color="$(tput setaf 2)"
sepcolor="$(tput setaf 6)"
reset="$(tput sgr0)"
diff $* |sed -e "s/^\\(<.*\$\\)/$file1color\\1$reset/;s/^\\(>.*\$\\)/$file2color\\1$reset/;s/^\\(---\$\\)/$sepcolor\\1$reset/"
2
  • 2
    And if you don't know off the top of your head what those parms to tput mean, do a man terminfo Nov 5, 2020 at 15:53
  • 1
    This saved me! I am on a system with diff 3.3, so it has no --color option (nor can I upgrade, or install colordiff, or anything new). Modifying the --new-line-format and etc. made it hard to keep the lines that normal diff -u chooses. This solution was exactly what I need.
    – Ajean
    Nov 2, 2022 at 21:58
1

You should have a look at the hl command available on github : git clone http://github.com/mbornet-hl/hl and on : http://www.flashnux.com/notes/page_000022_US.html

hl is a Linux command written in C, especially designed to color a text file or the output of a command. You can use up to 42 colors simultaneously, and use a configuration file to simplify command lines. You can colorize the output of every command that can be piped to another one. And if you know what regular expressions are, it will be very easy for you to use. You can use the man page to understand how to use it.
hl is very easy to use and to configure. You even can use the hl_generic script to colorize commands output without modifying their syntax.
You can, for example, colorize the output of the diff command just by typing your usual command :

diff file1 file2

If you need some help, just send me an e-mail.
Regards.

1

Just a note: to get the "side-by-side" output you need "--color=always". You can also paginate it with less and retain the colored output:

diff -y --color=always file1 file2 | less -R

And yet another hint: try to keep the "--color=always" switch at the end. Reason? With dmesg from util-linux 2.27.1:

dmesg --human --color=always | less -R    # works
dmesg --color=always --human | less -R    # doesn't work
1

There is a really neat tool built with python on Github at the moment called icdiff. Produces nice coloured outputs which are also “severity” aware. I use it all the time, well worth checking out.

1

Install Generic Colouriser (grc) and:

grc diff file1 file2

Available on both Linux and MacOS.

1
  • this didn't do anything for me, on WSL Ubuntu 18.04 using Windows Terminal 2
    – zaf187
    May 28, 2021 at 23:49
0

If you're on an apline linux container and don't want/can't pull down these other tools, this might work in a pinch.

RED="\\\033[0;31m"
GREEN="\\\033[0;32m"
OFF="\\\033[0m"
DIFF=$(diff --label "GOT" <(echo "$OUTPUT") --label "EXPECTED" <(echo "$EXPECTED_OUTPUT"))
printf -- "$(echo "$DIFF" | sed "s|^-|$RED-|g" | sed "s|^+|$GREEN+|g" | sed "s|$|$OFF|g")"

Here's some sample output.

sample output

0

diff 3.4+ can colorize its output in some modes like diff -u, diff -c. Also the pure shell script is available https://github.com/ildar-shaimordanov/colordiff. It does almost the same work as the Perl https://github.com/daveewart/colordiff.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .