patch와 diff를 사용하여 두 파일을 병합하고 충돌을 자동으로 해결하는 방법 가라. a.xml <resources> <color

diff와 patch에 대해 읽었지만 필요한 것을 적용하는 방법을 알 수 없습니다. 나는 그것이 매우 간단하다고 생각하므로 내 문제를 보여주기 위해이 두 파일을 가져 가라.

a.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. 행에 이름 태그는 동일하지만 값이 다른 경우 두 번째 값을 가져옵니다

이 작업을 bash 스크립트 안에 적용하고 싶기 때문에 다른 프로그램이 더 적합하다면 diff와 patch를 반드시 수행 할 필요는 없습니다.



답변

당신은 이것을 필요 patch로 하지 않습니다 ; 변경 사항을 추출하여 파일의 변경되지 않은 부분으로 전송하기위한 것입니다.

두 버전의 파일을 병합하는 도구는 merge이지만 @vonbrand, 기록한 것처럼 두 버전이 서로 다른 “기본”파일이 필요합니다. 병합하지 않고 병합하려면 다음 diff과 같이 사용 하십시오.

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

다음과 같이 C 스타일 #ifdef/ #ifndef“전 처리기”명령 에서 각 변경 사항을 묶습니다 .

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

두 파일간에 선이나 영역이 다른 경우 다음과 같은 “충돌”이 발생합니다.

#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사용하지 않는 한 파일 중 하나를 내부 편집합니다 -p. 설명서를 읽으십시오).


답변

merge(1) 아마 당신이 원하는 것에 더 가깝지만 두 파일의 공통 조상이 필요합니다.

그것을하는 (더러운!) 방법은 다음과 같습니다.

  1. 첫 번째 줄과 마지막 줄 grep(1)을 제거하고 사용 하여 제외하십시오.
  2. 결과를 함께 스매시
  3. sort -u 정렬 된 목록을 남기고 중복을 제거합니다.
  4. 첫 번째 / 마지막 줄 바꾸기

흠 … 선을 따라 뭔가 :

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

할 수 있습니다.


답변

sdiff (1)-파일 차이를 나란히 병합

--output옵션을 사용하면 두 파일을 대화식으로 병합합니다. 간단한 명령 을 사용 하여 변경을 선택하거나 변경을 편집합니다.

EDITOR환경 변수가 설정되어 있는지 확인해야합니다 . “eb”와 같은 명령의 기본 편집기는 일반적으로 ed라인 편집기 입니다.

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

답변

최대 10 개의 파일을 병합 하는 간단한 솔루션은 다음과 같습니다 .

#!/bin/bash

strip(){
    i=0
    for f; do
        sed -r '
            /<\/?resources>/ d
            s/>/>'$((i++))'/
        ' "$f"
    done
}

strip "$@" | sort -u -k1,1 -t'>' | sed '
    1 s|^|<resources>\n|
    s/>[0-9]/>/
    $ a </resources>
'

먼저 오는 인수가 우선권을 가지 므로 다음을 호출해야합니다.

script b.xml a.xml

b.xml대신 공통 값을 유지 a.xml합니다.

script b.xml a.xml 야당:

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

답변

또 다른 끔찍한 해킹-단순화 할 수는 있지만 : 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>"

답변

좋아, 두 번째 시도, 이제 Perl에서 ( 생산 품질이 아니라 검사하지 않음) :

#!/usr/bin/perl

open(A, "a.xml");

while(<A>) {
  next if(m;^\<resource\>$;);
  next if(m;^\<\/resource\>$;);
  ($name, $value) = m;^\s*\<color\s+name\s*\=\s*\"([^"]+)\"\>([^<]+)\<\/color\>$;;
  $nv{$name} = $value if $name;
}

close(A);

open(B, "b.xml");

while(<B>) {
  next if(m;^\<resource\>$;);
  next if(m;^\<\/resource\>$;);
  ($name, $value) = m;^\s*\<color\s+name\s*\=\*\"([^"]+)\"\>([^<]+)\<\/color\>$;;
  $nv{$name} = $value if $name;
}

close(B);

print "<resource>\n";
foreach (keys(%nv)) {
    print "   <color name=\"$_\">$nv{$_}</color>\n";
}
print "</resource>\n";

답변

cut과 grep을 사용하는 또 다른 방법은 … (a.xml b.xml을 인수로 사용함)

#!/bin/bash

zap='"('"`grep '<color' "$2" | cut -d '"' -f 2 | tr '\n' '|'`"'")'
echo "<resources>"
grep '<color' "$1" | grep -E -v "$zap"
grep '<color' "$2"
echo "</resources>"