पैच का उपयोग कैसे करें और दो फ़ाइलों को मर्ज करने के लिए कैसे करें और स्वचालित रूप से विरोधों को हल करें


19

मैंने अंतर और पैच के बारे में पढ़ा है लेकिन मैं यह नहीं समझ सकता कि मुझे क्या चाहिए। मुझे लगता है कि यह बहुत सरल है, इसलिए मेरी समस्या को दिखाने के लिए इन दो फाइलों को लें:

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. यदि किसी पंक्ति में समान नाम का टैग है लेकिन एक भिन्न मान है, तो दूसरे से मान लें

मैं इस कार्य को बैश स्क्रिप्ट के अंदर लागू करना चाहता हूं, इसलिए इसे अलग और पैच के साथ करने की आवश्यकता नहीं होनी चाहिए, अगर एक और प्रोग्राम एक बेहतर फिट है


diffआपको बता सकता है कि कौन सी लाइनें एक फ़ाइल में हैं, लेकिन दूसरी नहीं, बल्कि पूरी लाइनों की ग्रैन्युलैरिटी पर। patchकेवल एक ही फाइल के समान परिवर्तन करने के लिए उपयुक्त है (शायद एक ही फाइल का एक अलग संस्करण, या एक पूरी तरह से अलग फाइल जहां प्रत्येक परिवर्तन के लिए लाइन नंबर और आसपास की लाइनें आपकी मूल फ़ाइल के समान हैं)। तो नहीं, वे इस कार्य के लिए विशेष रूप से उपयुक्त नहीं हैं। आप एक नज़र रखना चाह सकते हैं wdiffलेकिन समाधान के लिए शायद एक कस्टम स्क्रिप्ट की आवश्यकता होती है। चूंकि आपका डेटा XML जैसा दिखता है, इसलिए आप कुछ XSL टूल की तलाश कर सकते हैं।
ट्रिपलए

1
कस्टम स्क्रिप्ट के साथ सभी उत्तर क्यों? विलय एक मानक और जटिल समस्या है, और इसके लिए अच्छे साधन हैं। पहिया को सुदृढ़ मत करो।
एलेक्सिस

जवाबों:


23

आपको इसकी आवश्यकता नहीं है patch; यह परिवर्तन निकालने और फ़ाइल के अपरिवर्तित भाग के बिना उन्हें भेजने के लिए है।

किसी फ़ाइल के दो संस्करणों को मर्ज करने का उपकरण है merge, लेकिन जैसा कि @vonbrandलिखा गया है, आपको "आधार" फ़ाइल की आवश्यकता है जिसमें से आपके दो संस्करणों को अलग किया गया है। इसके बिना एक मर्ज करने के लिए, diffइस तरह का उपयोग करें:

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

यह सी-स्टाइल #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। मैनुअल पढ़ें)।


मैं कुछ के लिए जोड़ा अगर मैं एक संघर्ष थाsed -e "s/^#else.*$/\/\/ conflict/g"
lockwobr

1
मुझे नहीं लगता कि यह एक अच्छा विचार है। जैसा कि मैंने अपने जवाब में लिखा है, आपको #elseसंघर्ष समाधान के दौरान संपादक में मैन्युअल रूप से लाइनों को हटाना चाहिए ।
एलेक्सिस

6

merge(1) संभवतः आप जो चाहते हैं, उसके करीब है, लेकिन इसके लिए आपकी दो फ़ाइलों के लिए एक सामान्य पूर्वज की आवश्यकता होती है।

ऐसा करने का एक (गंदा!) तरीका है:

  1. पहली और आखिरी लाइनों से छुटकारा पाएं, grep(1)उन्हें बाहर करने के लिए उपयोग करें
  2. परिणाम एक साथ तोड़
  3. sort -u एक छँटाई सूची छोड़ देता है, डुप्लिकेट को समाप्त करता है
  4. पहली / अंतिम पंक्ति बदलें

हम्म ... लाइनों के साथ कुछ:

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

शायद चलेगा।


इस विशेष उदाहरण में काम करता है, लेकिन सामान्य रूप से नहीं: यदि सॉर्ट का name in_b_but_different_valमान #00AABBऊपर रखा जाएगा और पहले वाले के बजाय दूसरा मूल्य मिटाता है
राफेल टी

इस मामले में इष्टतम समाधान के लिए आपको XML को पार्स करना होगा, असली XML पार्सर के ऊपर हैक्स नहीं है, और उसी से एक नया मर्ज किए गए XML आउटपुट का उत्पादन करेगा। diff / पैच / सॉर्ट आदि सभी हैक केवल "विशेष उदाहरणों" के अनुरूप होते हैं, एक सामान्य समाधान के लिए वे बस गलत उपकरण हैं
frostschutz

@alzheimer, हमें दिखाने के लिए कुछ सरल कोड़ा मारें ...
vonbrand

जाहिरा तौर diff3पर उसी तरह काम करता है। एक सामान्य पूर्वज फ़ाइल की आवश्यकता है। कोई सरल सीएलआई उपकरण क्यों नहीं है जो सिर्फ 2 फाइलों को एक साथ diffदिखाता है जो कि शो पर आधारित है ।
CMCDragonkai

5

sdiff (1) - फ़ाइल अंतर के साइड-बाय-साइड मर्ज

--outputविकल्प का उपयोग करें , यह अंतःक्रियात्मक रूप से किसी भी दो फ़ाइलों को मर्ज करेगा। आप किसी परिवर्तन का चयन करने या किसी परिवर्तन को संपादित करने के लिए सरल आदेशों का उपयोग करते हैं।

आपको यह सुनिश्चित करना चाहिए कि EDITORपर्यावरण चर सेट किया गया है। "Eb" जैसी कमांड के लिए डिफ़ॉल्ट एडिटर आमतौर पर edएक लाइन एडिटर होता है

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

1
मैं vimEDITOR के रूप में बेहतर के रूप में उपयोग कर पाते हैं । लेकिन यह सबसे अच्छा समाधान है, यह diffकमांड के साथ भी आता है!
CMCDragonkai

1

यहां एक सरल उपाय जो 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>

1

एक और भयानक हैक - सरलीकृत किया जा सकता है, लेकिन: पी

#!/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>"

0

ठीक है, दूसरे की कोशिश, अब पर्ल (में नहीं उत्पादन गुणवत्ता, कोई जाँच!):

#!/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";

0

एक और, कट और 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>"

echoडिफ़ॉल्ट क्रिया है, इसलिए बहुत ही शानदार xargs echoहै। तुम बस tr '\n' '|'वैसे भी क्यों नहीं ?
12

अच्छा बिंदु - यह सिर्फ एक त्वरित हैक है। मैं इसे संपादित करूंगा।
13
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.