patchとdiffを使用して2つのファイルをマージし、自動的に競合を解決する方法

patchとdiffを使用して2つのファイルをマージし、自動的に競合を解決する方法

違いとパッチについて読みましたが、必要なものを適用する方法がわかりません。私はそれが非常に簡単になりたいので、私の問題を示すために、次の2つのファイルを使用してください。

XMLファイル

<resources>
   <color name="same_in_b">#AAABBB</color>
   <color name="not_in_b">#AAAAAA</color>
   <color name="in_b_but_different_val">#AAAAAA</color>
   <color name="not_in_b_too">#AAAAAA</color>
</resources>

b.xml

<resources>
   <color name="same_in_b">#AAABBB</color>
   <color name="in_b_but_different_val">#BBBBBB</color>
   <color name="not_in_a">#AAAAAA</color>
</resources>

私は次のような出力が必要です(順序は重要ではありません)。

<resources>
   <color name="same_in_b">#AAABBB</color>
   <color name="not_in_b">#AAAAAA</color>
   <color name="in_b_but_different_val">#BBBBBB</color>
   <color name="not_in_b_too">#AAAAAA</color>
   <color name="not_in_a">#AAAAAA</color>
</resources>

マージには、次の簡単な規則に従うすべての行を含める必要があります。

  1. ファイル内のすべての行のみ
  2. 1行に同じ名前タグがあるが値が異なる場合は、2行目から値を取得します。

これをbashスクリプトに適用したいので、他のプログラムがより適切な場合は、diffとパッチを使用して必ずしも行う必要はありません。

答え1

これは必要ありませんpatch。変更を抽出し、ファイルの未変更部分なしで送信するために使用されます。

2つのバージョンのファイルをマージするためのツールがありますが、作成されたmergeように@vonbrand2つのバージョンを分岐するには「デフォルト」ファイルが必要です。なしでマージするには、diff次のように使用します。

diff -DVERSION1 file1.xml file2.xml > merged.xml

#ifdef#ifndefこれには、次のCスタイル/「プリプロセッサ」コマンドのすべての変更セットが含まれます。

#ifdef VERSION1
<stuff added to file1.xml>
#endif
...
#ifndef VERSION1
<stuff added to file2.xml>
#endif

2つのファイルの行または領域が異なる場合、次のような「衝突」が発生します。

#ifndef VERSION1
<version 1>
#else /* VERSION1 */
<version 2>
#endif /* VERSION1 */

したがって、出力をファイルに保存してエディタで開きます。#else表示されるすべての場所を検索して手動で解決してください。次に、ファイルを保存して実行して、残りのgrep -v合計#if(n)def#endifを削除します。

grep -v '^#if' merged.xml | grep -v '^#endif' > clean.xml

今後は元のバージョンのファイルを保存してください。merge追加情報があれば、より良い結果が得られます。 (ただし、注意してください。mergeを使用しない限り、これらのファイルの1つを内部で編集してください-p。マニュアルをお読みください)。

答え2

sdiff(1) - ファイルの違いを並べてマージ

この--outputオプションを使用すると、両方のファイルを対話式にマージします。あなたは簡単に使用します注文する変更または変更の編集を選択します。

EDITOR環境変数が設定されていることを確認する必要があります。 「eb」などのコマンドのデフォルトエディタは、通常、次のようになります。ed、ラインエディタ

EDITOR=nano sdiff -o merged.txt file1.txt file2.txt

答え3

merge(1)おそらくあなたが望むものに近いですが、これを行うには両方のファイルに共通の祖先が必要です。

1つの(汚い!)方法は次のとおりです。

  1. 最初の行と最後の行を削除するには、grep(1)次を使用して除外します。
  2. 結果を1つにまとめる
  3. sort -u並べ替えられたリストをそのままにして重複項目を削除します。
  4. 最初/最後の行を置き換える

まあ...おそらく次のようになります。

echo '<resources>'; grep -v resources file1 file2 | sort -u; echo '</resources>'

そうかもしれませんね。

答え4

別の恐ろしいハッキングは単純化することができます。 :P

#!/bin/bash

i=0

while read line
do
    if [ "${line:0:13}" == '<color name="' ]
    then
        a_keys[$i]="${line:13}"
        a_keys[$i]="${a_keys[$i]%%\"*}"
        a_values[$i]="$line"
        i=$((i+1))
    fi
done < a.xml

i=0

while read line
do
    if [ "${line:0:13}" == '<color name="' ]
    then
        b_keys[$i]="${line:13}"
        b_keys[$i]="${b_keys[$i]%%\"*}"
        b_values[$i]="$line"
        i=$((i+1))
    fi
done < b.xml

echo "<resources>"

i=0

for akey in "${a_keys[@]}"
do
    print=1

    for bkey in "${b_keys[@]}"
    do
        if [ "$akey" == "$bkey" ]
        then
            print=0
            break
        fi
    done

    if [ $print == 1 ]
    then
        echo "  ${a_values[$i]}"
    fi

    i=$(($i+1))
done

for value in "${b_values[@]}"
do
    echo "  $value"
done

echo "</resources>"

関連情報