vim比較目錄diff

來源:互聯網
上載者:User

標籤:工具   vim   

雖然現在有很多圖形介面的diff工具,但對於有命令列情節的人來說,當飛快的在terminal下敲擊鍵盤時,總不希望再拿滑鼠去點擊其它地方,況且有時候圖形介面佔用資源多,我的MBA就經常啟動diffmerge時卡住,但vimdiff又只能在一個標籤裡比較一組檔案的diff,如果想比較兩個目錄下檔案的diff,它就顯得無能為力了

假設我們要實現一個工具叫diffdir,先讓我們腦洞開啟設想一下它應該是怎樣的

  1. 我希望能列出兩個目錄下檔案名稱相同但內容不同的所有檔案,並進行編號
  2. 我希望通過選擇編號,開啟需要比較diff的檔案
  3. 如果想比較多組檔案的diff,我希望每個vim標籤開啟一組檔案比較
  4. 最好能過濾掉非文字檔,因為我不希望用vim開啟一對二進位亂碼
  5. 最好還能有互動,我可以選擇只查看我感興趣的檔案,而不是一次開啟所有檔案的diff,當退出vim時我還可以繼續選擇

假設有兩個目錄分別是A和B,目錄結構如下

A├── file1├── file2└── file3   

B和A目錄結構以及對應檔案名稱都相同,其中file1和file2的內容不同,file3內容相同,那麼當我們運行diffdir A B時,它應該是這樣的介面

當我們選擇編號1時,vim會開啟一個標籤對比兩個目錄下file1的差異
當我們選擇1,21-2時,vim會開啟兩個標籤分別比較file1和file2的差異
由於這個例子有diff的檔案數量較少,我們還可以選擇a一次開啟所有檔案的diff
如果diff檔案個數較多,我們可以分批開啟,並且當我們退出vim後還可以繼續選擇

接下來是實現

vim比較檔案diff

我們都知道vimdiff的用法,其實vimdiff A/file1 B/file1等價於vim -d A/file1 B/file2,又或者更原始一點,我們可以分兩步來比較兩個檔案的diff

  1. 執行vim A/file1
  2. 在normal模式下輸入:vertical diffsplit B/file1

雖然人們不會用這麼麻煩的命令去比價檔案的diff,但往往最基本的命令反而能組合出更多的功能,就像搭積木一樣,我們只需要幾個基本的形狀,就可以通過自己的想象搭建多彩的世界,而vim的這些基本命令就像積木一樣,我們要做的是利於好這些積木

vim在新標籤比較檔案diff

假設我們已經用上面的命令開啟了vim並比較file1的diff,如果我們希望建立一個標籤來比較file2的diff呢,還是要用到基本的ex命令

  1. 在normal模式下執行:tabnew A/file2
  2. 在normal模式下執行:vertical diffsplit B/file1
vim批量執行命令

以上兩個樣本就是我們需要的積木,有了積木,我們就可以組合出強大的命令,現在要做的是同時開啟兩組檔案的diff,並且每個標籤一組diff

通過查看vim協助我們發現vim有如下兩個參數

-c <command>         載入第一個檔案後執行 <command>-S <session>         載入第一個檔案後執行檔案 <session>

這兩個參數都可以讓vim啟動時執行一些命令,其中-c是從參數讀取命令,-S是從檔案讀取命令,於是我們就可以將需要執行的命令存入檔案,啟動vim時通過-S參數載入該檔案,就能達到我們批量執行命令的目的。假設我們需要開啟兩個標籤,分別比較A,B目錄下file1和file2的diff,事先建立vim.script如下(檔案名稱隨意,最好採用絕對路徑,以免受到vim配置裡autochdir的影響)

edit A/file1vertical diffsplit B/file1tabnew A/file2vertical diffsplit B/file2

然後執行vim -S vim.script,看看是否如你所願,開啟了兩個標籤,分別比較file1和file2的diff。注意,為了

最終實現

既然有了這些積木,那我們就可以靈活的根據需要編寫指令碼實現我們的需求,下面是我最終的實現,也可以在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 $2 ];then    echo "$1 or $2 is not derectory!"    exit 1fi## 注意,Mac的readlink程式和GNU readlink功能不同,Mac需要下載greadlinkarg1=`greadlink -f $1`arg2=`greadlink -f $2`tmp_dir=/tmp/tmp.$$rm -rf $tmp_dirmkdir -p $tmp_dir || exit 0#echo $tmp_dirtrap "rm -rf $tmp_dir; exit 0" SIGINT SIGTERM## 注意,Mac和Linux的MD5程式不同,請根據需求使用,這裡是Mac版的用法function get_file_md5{    if [ $# -ne 1  ];then        echo "get_file_md5 arg num error!"        return 1    fi    local file=$1    md5 $file | awk -F"=" ‘{print $2}‘}function myexit{    rm -rf $tmp_dir    exit 0}function show_diff{    if [ $# -ne 1 ];then        return 1    fi    local diff_file=$1    echo "diff file:"    printf "    %-55s  %-52s\n" $arg1 $arg2    if [ -f $tmp_dir/A_ony_file ];then        awk ‘{printf("    [%2d] %-50s\n", NR, $1)}‘ $tmp_dir/A_ony_file        python -c ‘print "-"*100‘    fi    awk ‘{printf("    [%2d] %-50s  %-50s\n", NR, $1, $1)}‘ $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 "$numbers" | awk -F"-" ‘{print $1}‘`        end=`echo "$numbers" | awk -F"-" ‘{print $2}‘`        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 >> $tmp_file        fi        if [ $? -ne 0 ];then        return 1        fi    done    awk -v dir1=$arg1 -v dir2=$arg2 ‘{    if (NR==1)        {        printf("edit %s/%s\nvertical diffsplit %s/%s\n", dir1, $0, dir2, $0)        }        else        {        printf("tabnew %s/%s\nvertical diffsplit %s/%s\n", dir1, $0, dir2, $0)        }    }‘ $tmp_file}############################################################## 擷取diff info#############################################################for file in `find $arg1 | grep -v "/\." | grep -v "^\."`do    file_relative_name=${file#$arg1/}    file $file | grep -Eq "text"    if [ $? -ne 0 ];then        continue    fi    if [ -f $arg2/$file_relative_name ];then        file $arg2/$file_relative_name | grep -Eq "text"        if [ $? -ne 0 ];then            continue        fi        md5_1=`get_file_md5 $file`        md5_2=`get_file_md5 $arg2/$file_relative_name`        if [[ "$md5_1" = "$md5_2" ]];then            continue        fi        ## file not same        echo "$file_relative_name" >> $tmp_dir/diff_file    else        echo "$file_relative_name" >> $tmp_dir/A_ony_file    fidone############################################################## 根據輸入標籤開啟用vim開啟檔案比較diff#############################################################if [ ! -f $tmp_dir/diff_file ];then    exitfishow_diff $tmp_dir/diff_filewhile truedo    echo -n "Please choose 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比較目錄diff

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.