Although there are many graphical interface diff tools, but for the command-line plot of people, when the fast terminal under the keyboard, always do not want to take the mouse to click elsewhere, and sometimes the graphical interface occupies a lot of resources, my MBA often started diffmerge when stuck, But Vimdiff can only compare a set of files in a single label, and if you want to compare the diff of files in two directories, it seems powerless.
Suppose we're going to implement a tool called Diffdir, let's just open up our brains and imagine what it's supposed to be.
- I would like to be able to list all files with the same file name but different contents in two directories and number them
- I want to open a file that needs to compare diff by selecting the number
- If you want to compare the diff of multiple sets of files, I want each vim tag to open a set of file comparisons
- It's better to filter out non-text files because I don't want to use vim to open a pair of binary garbled characters
- It's best to have interactivity, I can choose to see only the files I'm interested in, not the diff of all the files at once, and when I quit VIM I can continue to choose
Let's say two directories are A and B, and the directory structure is as follows
A├── file1├── file2└── file3
b and a directory structure and the corresponding filenames are the same, where file1 and file2 content is different, file3 content is the same, then when we run diffdir A B
, it should be such an interface
When we select the number 1 o'clock, Vim opens a label to compare the differences of file1 in two directories
When we select 1,2
or 1-2
, VIM will open two tabs to compare the differences between File1 and File2 respectively.
Since this example has a smaller number of diff files, we can also select a to open diff for all files at once
If the number of diff files is large, we can open them in batches, and when we exit vim, we can continue to select
The next step is to implement
Vim Compare file diff
We all know that the usage of Vimdiff is actually vimdiff A/file1 B/file1
equivalent to vim -d A/file1 B/file2
, or more primitive, that we can compare the diff of two files in two steps.
- Perform
vim A/file1
- Enter in normal mode
:vertical diffsplit B/file1
Although people will not use such a troublesome command to compare file diff, but often the most basic command can be combined with more functions, like building blocks, we only need a few basic shapes, we can build a colorful world through their own imagination, and vim these basic commands like building blocks, What we're going to do is to make these bricks good.
Vim Compare file diff in new label
Suppose we've opened vim with the above command and compared File1 diff, if we want to create a new label to compare File2 diff, or to use the basic EX command
- Execute in Normal mode
:tabnew A/file2
- Execute in Normal mode
:vertical diffsplit B/file1
Vim Batch Execution command
The above two examples are the bricks we need, with the building blocks, we can assemble a powerful command, now to do is to open both sets of file diff, and each label a set of diff
By looking at Vim to help us discover that Vim has the following two parameters
-c <command> 加载第一个文件后执行 <command>-S <session> 加载第一个文件后执行文件 <session>
Both parameters allow Vim to execute some commands at startup, where-C is the command read from the parameter,-S is read from the file command, so we can put the command to be executed into a file, when the start of vim with the-s parameter to load the file, we can achieve the purpose of bulk execution of the command. Suppose we need to open two labels, compare the diff of File1 and file2 in A/b directory, create the Vim.script as follows (the file name is arbitrary, it is best to use absolute path, so as not to be affected by the Autochdir in Vim configuration)
edit A/file1vertical diffsplit B/file1tabnew A/file2vertical diffsplit B/file2
Then execute vim -S vim.script
to see if, as you wish, two tabs are opened, comparing the diff of file1 and file2 respectively. Note that in order to
Final implementation
Now that we have these bricks, we have the flexibility to write scripts to meet our needs, and here's my final implementation, and I can view the source code on GitHub.
Https://github.com/handy1989/vim/blob/master/diffdir
#!/bin/bashif [$#-ne 2];then echo "usage:$0 dir1 dir2" Exit 1fiif [!-D $1-o!-D $];then echo "$ or $ i s not derectory! " Exit 1fi## Note that the Mac Readlink program and the GNU Readlink feature are different, Mac needs to download greadlinkarg1= ' greadlink-f $ ' arg2= ' greadlink-f ' tmp_dir=/ tmp/tmp.$ $rm-rf $tmp _dirmkdir-p $tmp _dir | | Exit 0#echo $tmp _dirtrap "Rm-rf $tmp _dir; Exit 0 "SIGINT sigterm## Note that Mac and Linux MD5 programs are different, please use according to demand, here is the use of Mac version of function get_file_md5{if [$#-ne 1];then ech o "get_file_md5 arg num error!" Return 1 fi local file=$1 MD5 $file | Awk-f "=" ' {print $} '}function myexit{rm-rf $tmp _dir exit 0}function show_diff{If [$#-ne 1];then re Turn 1 fi local diff_file=$1 echo "diff file:" printf "%-55s%-52s\n" $arg 1 $arg 2 If [-F $tmp _dir/a_o Ny_file];then awk ' {printf ("[%2d]%-50s\n", NR, $ $)} ' $tmp _dir/a_ony_file python-c ' print '-' *100 ' Fi awk ' {printf ("[%2d]%-50s%-50s\n", NR, $ $, $)} ' $diff _file Echo "(s): Show diff Files (a): Open all diff files (q): Exit" echo}function check_value{local diff_file=$1 local value =$2 tmp_file= $tmp _dir/tmp_file > $tmp _file for numbers in ' Echo ' $value | Tr ', ' Do nf= ' echo ' $numbers ' | Awk-f "-" ' {print NF} ' if [$nf-ne 1-a $nf-ne 2];then return 1 fi begin= ' echo ' $numbe RS "| Awk-f "-" ' {print $} ' end= ' echo ' $numbers ' | Awk-f "-" ' {print $} ' if [-Z ' $end '];then sed-n $begin ' P ' $diff _file >> $tmp _file Else If ["$end"-lt $begin];then return 1 fi sed-n $begin ', ' $end ' P ' $diff _file >> $tm P_file fi if [$?-ne 0];then return 1 fi done awk-v dir1= $arg 1-v dir2= $arg 2 ' {if (nr==1) {printf ("Edit%s/%s\nvertical diffsplit%s/%s\n", Dir1, $, Dir2, $)} else {printf ( "Tabnew%s/%s\nvertical diffsplit%s/%s\n", Dir1, $ A, DIR2, $)}} ' $tmp _file}############################################################## get diff info################## ########################################## #for file in ' Find $arg 1 | Grep-v "/\." | Grep-v "^\." ' Do file_relative_name=${file# $arg 1/} file $file | Grep-eq "Text" If [$?-ne 0];then Continue fi if [-f $arg 2/$file _relative_name];then file $arg 2/$file _relative_name | Grep-eq "Text" If [$?-ne 0];then Continue fi md5_1= ' get_file_md5 $file ' md5_2= ' GET_FILE_MD5 $arg 2/$file _relative_name ' If [["$md 5_1" = "$MD 5_2"]];then continue fi # # F Ile not same echo "$file _relative_name" >> $tmp _dir/diff_file Else echo "$file _relative_name" >& Gt $tmp _dir/a_ony_file fidone############################################################## Open file comparison with vim based on input tag diff# ########################################################### #if [!-F $tmp _dir/diff_file];tHen exitfishow_diff $tmp _dir/diff_filewhile truedo echo-n "Please choose the file number list (like this:1,3-4,5):" Read value if [["$value" = "s"]] | | [["$value" = "S"]];then show_diff $tmp _dir/diff_file continue elif [["$value" = "Q"]] | | [["$value" = "Q"]];then myexit elif [["$value" = "a"]] | | ["$value" = "A"];then value= "1-$" fi vim_script= ' Check_value $tmp _dir/diff_file "$value" 2>/dev/null ' If [$?-ne 0];then echo "Invalid parameter[$value]!" else vim-c "$vim _script" Fidone
Vim Comparison catalog diff