Diff and Merge N Files

I was stuck with this problem yesterday where I need to compare more than three files, as shown below. That threshold hit the limit of Meld, my favourite visual tool to diff and merge code. I was intrigued about the limitation and decided to check the limitation of the diff tools in GNU/Linux world.

Before that, let's create a number of files to be compared.
$ for i in {1..6}; do seq 0 $i | xargs printf "%06d\n" > $i.txt; done

So right now we have six plain text files and one of the content of the file is shown below.
$ ls *.txt
1.txt  2.txt  3.txt  4.txt  5.txt  6.txt
$ cat 6.txt 
000000
000001
000002
000003
000004
000005
000006

First, the default diff console tool. Nope, maximum two files only.
$ diff {1..6}.txt
diff: extra operand '3.txt'
diff: Try 'diff --help' for more information.

$ diff {1..2}.txt
2a3
> 000002

Next, let's try vimdiff. As you can see from the result and screenshot below, although six files are shown, only four can be merged.
$ vimdiff {1..6}.txt
"6.txt" 7L, 49C
E96: Can not diff more than 4 buffers
E96: Can not diff more than 4 buffers
Press ENTER or type command to continue


Can my favourite Meld works with more than three files? Nope.
$ meld {1..6}.txt
Usage: 
  meld                              Start with an empty window
  meld                 Start a version control comparison
  meld   []       Start a 2- or 3-way file comparison
  meld   [] Start a 2- or 3-way folder comparison

Error: too many arguments (wanted 0-3, got 6)

How about xxdiff? Nope again, max is three files but the error message is way more informative.
$ xxdiff {1..6}.txt                                                                                                                
xxdiff (cmdline.cpp:762): 
You can specify at most 3 filenames.
Extra arguments: " 4.txt 5.txt 6.txt"
Use 'xxdiff --help' for more information.

Diffuse? A new tool that I've recently made aware of. It seems we have a winner here!


Kdiff3. Totally ignore the remaining three files. No message what so ever. See screenshot below.
Kompare. The program won't even start properly.


Expanding RPM's Build-in Macro Values.

While looking into Drupal directory structures in Fedora, I stumbled upon this file, /usr/lib/rpm/macros.d/macros.drupal7, which seems to be the configuration file for RPM command.
$ cat /usr/lib/rpm/macros.d/macros.drupal7 
%drupal7            %{_datadir}/drupal7
%drupal7_modules    %{drupal7}/modules
%drupal7_themes     %{drupal7}/themes
%drupal7_libraries  %{_sysconfdir}/drupal7/all/libraries

# No-op macro to allow spec compatibility with RPM < 4.9 (no fileattrs)
%drupal7_find_provides_and_requires %{nil}

Let's try to expand the values of the above built-in RPM's macros.
$ cat /usr/lib/rpm/macros.d/macros.drupal7  | awk '{print $1}' | grep ^% | xargs -I % sh -c 'echo -en "%\t"; rpm --eval %' | column -t
%drupal7                             /usr/share/drupal7
%drupal7_modules                     /usr/share/drupal7/modules
%drupal7_themes                      /usr/share/drupal7/themes
%drupal7_libraries                   /etc/drupal7/all/libraries
%drupal7_find_provides_and_requires

Why not create a Bash function for the above command instead? Put this in your $HOME/.bashrc file.
# expanding the value of the rpm's built-in macros.
function rpm_macro() {
    if [[ -z "$1" ]]; then
        echo "No filename supplied"
    else
        cat $1 | awk '{print $1}' | grep ^% |\
        xargs -I % sh -c 'echo -en "%\t"; rpm --eval %' | column -t  
    fi  
}

Try out our newly created bash function.
$ rpm_macro macros.drupal7 
%drupal7                             /usr/share/drupal7
%drupal7_modules                     /usr/share/drupal7/modules
%drupal7_themes                      /usr/share/drupal7/themes
%drupal7_libraries                   /etc/drupal7/all/libraries
%drupal7_find_provides_and_requires