एक इन-प्लेस प्रतिस्थापन का प्रदर्शन कैसे करें जो केवल उन फ़ाइलों का बैकअप बनाता है जिन्हें बदल दिया गया था?


13

मैंने वर्तमान कार्यशील निर्देशिका में सभी फ़ाइलों में उपयोग किए जाने वाले शब्द को बदलने के लिए निम्नलिखित कार्य किया:

$ find . -type f -print0 | xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

इसने शब्द प्रतिस्थापन का प्रदर्शन किया लेकिन इसने .bupफाइलों की फाइलें भी बनाईं जिनमें कभी Ms. Johnsonस्ट्रिंग नहीं थी ।

इन सभी अनावश्यक बैकअप को बनाए बिना मैं प्रतिस्थापन कैसे कर सकता हूं?



सहेजने और बाहर निकलने से पहले exचल रहा है, और सशर्त रूप से (केवल अगर फ़ाइल बदल दी जाती है) एक बेहतर दृष्टिकोण संभव है :!cp '%' '%.bup'। यह देखने लायक हो सकता है।
वाइल्डकार्ड

मैंने स्टैक एक्सचेंज पर अपने विचार के बारे में एक प्रश्न लिखा था vi
वाइल्डकार्ड

जवाबों:


6

आप यह सुनिश्चित करने के लिए फ़ाइलों की सामग्री की जांच कर सकते हैं कि एक प्रतिस्थापन sedउन पर काम करते समय होगा:

find . \
    -type f \
    -exec grep -q 'Ms. Johnson' {} \; \
    -print0 |
xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

यदि आप इसके बारे में वास्तव में चतुर होना चाहते हैं, तो आप इसका उपयोग कर सकते हैं find:

grep -Z -l -r 'Ms. Johnson' |
    xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

1
मुझे लगता है कि आपको इसमें '{}'अपने से ठीक पहले की जरूरत \;है -exec
जैंडर

8

ढूँढें के पास एक -execऑपरेटर है जो एक मनमाना कमांड निष्पादित करता है। इससे भी बेहतर, -execएक परीक्षण है , इसलिए आप कई -execएस को एक साथ चेन कर सकते हैं, और यदि पहले के कमांड विफल हो जाते हैं, तो बाद में निष्पादित नहीं होंगे। स्ट्रिंग {}को वर्तमान फ़ाइल नाम के साथ बदल दिया जाता है, और ;कमांड के अंत को चिह्नित करता है। शेल हस्तक्षेप से बचने के लिए आपको दोनों को उद्धृत करना चाहिए।

इसलिए:

find . -type f \
    -exec grep -q 'Ms. Johnson' '{}' \; \
    -exec sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g' '{}' \;

मुझे कभी भी नंगे {} के प्रयोग से कोई समस्या नहीं हुई है।
एम्फ़ैटेमाचिन

1
@amphetamachine: न तो मेरे पास है, लेकिन मैन पेज इसका सुझाव देता है। यह एक csh चीज हो सकती है, या ऐसे गोले हो सकते हैं (बैश नहीं और POSIX नहीं) जो {}ब्रेस विस्तार करते समय अशक्त स्ट्रिंग तक फैलते हैं ।
जैंडर

4

मैंने मैन पेज देखा और इसे सीधे करने के लिए कोई रास्ता नहीं देखा sed, जैसा कि मुझे यकीन है कि आपने पूछने से पहले किया था। मुझे grep का उपयोग करके इसके आसपास काम करने के कई तरीके दिखाई देते हैं, लेकिन मुझे लगता है कि यह सबसे आसान है:

grep -rlZ "Ms. Johnson" . | xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

-rrecurse
-lप्रिंट फ़ाइल नाम केवल
-Zशून्य वाले नामों खत्म


-1

लगता है कि आपको उन फ़ाइलों की सूची बनाने की आवश्यकता है जो पहले आपके खोज शब्दों से मेल खाती हैं।

search="test"
for match in $(find -type f -exec grep -l $search "{}" \;)
do sed -i'.bup' -e "/$search/ s/$search/Mrs. Melbin/g" "$match"
done

आप .पहले तर्क के रूप में भूल गए find। इसके अलावा, जैसा कि मैंने खुद को बहुत पहले सूचित नहीं किया था, आपको वास्तव में बोली लगाने या भागने की जरूरत नहीं है{}
केविन

फ़ाइलों की एक सूची उत्पन्न न करें और उस पर कमांड प्रतिस्थापन करें। पहले findफ़ाइलों की एक नई-अलग-अलग सूची उत्पन्न करता है, फिर शेल इस सूची को किसी भी व्हाट्सएप (न केवल नईलाइन्स) पर तोड़ता है और फिर शेल प्रत्येक शब्द को एक ग्लोब पैटर्न के रूप में मानता है। यह केवल तभी काम करता है जब आपकी फ़ाइल के नाम में व्हॉट्सएप न हो या \[?*। इस पृष्ठ पर अन्य उत्तर बताते हैं कि यह कैसे सही ढंग से करना है।
गाइल्स का SO- बुराई पर रोक '

@ केविन .अनावश्यक है (कम से कम लिनक्स पर पाए जाने वाले) के साथ अनावश्यक है क्योंकि यह माना जाता है कि जब कोई रास्ता एक तर्क पारित नहीं होता है।
laebshade
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.