कैसे पकड़ें और बदलें


252

मुझे एक निर्देशिका में सभी फ़ाइलों और उपनिर्देशिकाओं के भीतर एक निर्दिष्ट स्ट्रिंग की पुन: खोज करने की आवश्यकता है और इस स्ट्रिंग को किसी अन्य स्ट्रिंग के साथ बदलें।

मुझे पता है कि इसे खोजने की आज्ञा इस तरह दिख सकती है:

grep 'string_to_find' -r ./*

लेकिन मैं string_to_findएक स्ट्रिंग के साथ हर उदाहरण को कैसे बदल सकता हूं ?


मुझे विश्वास नहीं है कि grep ऐसा कर सकता है (मैं गलत हो सकता है)। आसान तरीके से रीप्ले करने के लिए सेड या पर्ल का इस्तेमाल किया जाएगा
मेमेंटो मोरी

2
उपयोग करने का प्रयास करेंsed -i 's/.*substring.*/replace/'
Eddy_Em

2
@Eddy_Em जो पूरी लाइन को रिप्लेस कर देगा। आपको प्रतिस्थापन के पहले और बाद में लाइन के हिस्से को पकड़ने के लिए समूहीकरण का उपयोग करने की आवश्यकता होती है और फिर प्रतिस्थापन लाइन में डाल दिया जाता है। sed -i 's/\(.*\)substring\(.*\)/\1replace\2/'
JStrahl


जवाबों:


249

एक अन्य विकल्प खोज का उपयोग करना है और फिर इसे sed के माध्यम से पास करना है।

find /path/to/files -type f -exec sed -i 's/oldstring/new string/g' {} \;

34
ओएस एक्स 10.10 टर्मिनल पर, पैरामीटर के लिए एक उचित विस्तार स्ट्रिंग -iकी आवश्यकता है। उदाहरण के लिए, find /path/to/files -type f -exec sed -i "" "s/oldstring/new string/g" {} \;वैसे भी, खाली स्ट्रिंग प्रदान करना अभी भी मैनुअल में वर्णित के विपरीत एक बैकअप फ़ाइल बनाता है ...
Eonil

10
मुझे "sed: RE त्रुटि: अवैध बाइट अनुक्रम" क्यों मिलता है। और हाँ, मैंने -i ""ओएस एक्स के लिए जोड़ा । यह अन्यथा काम करता है।
टैको

2
मेरे पास macOS 10.12 पर अवैध बाइट अनुक्रम मुद्दा था, और इस प्रश्न / उत्तर ने मेरा मुद्दा हल किया: stackoverflow.com/questions/19242275/…
abeboparebop

3
यह हर फ़ाइल को छूता है ताकि फ़ाइल समय संशोधित हो; और रूपांतरित होता से अंत लाइन CRLFकरने के लिए LFविंडोज पर।
jww

183

मुझे जवाब मिल गया।

grep -rl matchstring somedir/ | xargs sed -i 's/string1/string2/g'

14
यह दो बार मिलान फ़ाइलों के माध्यम से स्कैन करेगा ... एक बार grepऔर फिर साथ sedfindविधि का उपयोग करना अधिक कुशल है लेकिन आपके द्वारा उल्लिखित यह विधि काम करती है।
cmevoli

41
ओएस एक्स पर आपको काम sed -i 's/str1/str2/g'करने के sed -i "" 's/str1/str2/g'लिए इसे बदलना होगा ।
jdf

6
इस विधि के साथ @cmevoli, grepसभी फ़ाइलों के माध्यम से जाती है और sedकेवल मिलान की गई फ़ाइलों को स्कैन करती है grepfindअन्य उत्तर में विधि के साथ , findपहले सभी फ़ाइलों को सूचीबद्ध करता है, और फिर sedउस निर्देशिका में सभी फ़ाइलों के माध्यम से स्कैन करेगा। तो यह विधि आवश्यक रूप से धीमी नहीं है, यह इस बात पर निर्भर करता है कि कितने मैच हैं और खोज गति में अंतर है sed, grepऔर find
joelostblom

4
इस तरह से आपको यह देखने की अनुमति देता है कि किस चीज से वास्तव में जगह मिलती है, असफलता के जोखिम को बहुत कम कर देता है, विशेष रूप से खुद की तरह rexx n00bs के लिए
Lennart Rolland

2
यह तब भी उपयोगी है जब आपका ग्रीप प्रतिस्थापन सेड की तुलना में अधिक चतुर है। उदाहरण के लिए ripgrep आज्ञा का पालन करता है। जबकि समकोण होता है जबकि sed नहीं करता है।
user31389

44

आप इसे इस तरह भी कर सकते हैं:

उदाहरण

grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g'

यह वर्तमान निर्देशिका के सापेक्ष सभी फाइलों में स्ट्रिंग ' विंडो ' की खोज करेगा और प्रत्येक फाइल में स्ट्रिंग की प्रत्येक घटना के लिए ' लिनक्स ' के साथ ' विंडो ' को बदलेगा ।


2
grepकेवल उपयोगी है अगर वहाँ फ़ाइलें जो संशोधित नहीं किया जाना चाहिए। sedसभी फ़ाइलों पर चलने से फ़ाइल की संशोधन तिथि अपडेट हो जाएगी लेकिन मिलान न होने पर सामग्री को अपरिवर्तित छोड़ दें।
ट्रिपल जू

@tripleee: सावधानी बरतें ... लेकिन [sed] अगर मैच नहीं होते हैं तो कंटेंट को अपरिवर्तित छोड़ दें " । उपयोग करते समय -i, मेरा मानना ​​है कि sedयह जिस फाइल को छूता है उसकी फाइल का समय बदल देता है, भले ही कंटेंट अपरिवर्तित हो। sedलाइन स्टेटिंग को भी कनवर्ट करता है । मैं sedएक git रेपो में विंडोज पर उपयोग नहीं करता क्योंकि सभी CRLFको बदल दिया जाता है LF
jww

इस कमांड को -i को यह बताने के लिए कि "इन-प्लेस प्रतिस्थापन के बाद कोई बैकअप फाइल नहीं बनेगी, कम से कम मैकोक्स में, कमांड की जरूरत है"। विवरण के लिए मैन पेज की जाँच करें। यदि आप एक बैकअप चाहते हैं, तो यह वह जगह है जहां आपने फ़ाइल के विस्तार को बनाया जाना है।
स्पाईनबेलर

31

यह ओएस एक्स पर मेरे लिए सबसे अच्छा काम करता है:

grep -r -l 'searchtext' . | sort | uniq | xargs perl -e "s/matchtext/replacetext/" -pi

स्रोत: http://www.praj.com.au/post/23691181208/grep-replace-text-string-in-files


यह पूर्ण है! ag के साथ भी काम करता है:ag "search" -l -r . | sort | uniq | xargs perl -e 's/search/replace' -pi

@sebastiankeller आपके पर्ल कमांड में अंतिम स्लैश का अभाव है, जो एक वाक्यविन्यास त्रुटि है।
ट्रिपल जू 11:16

3
sort -uयहां तक ​​कि इसका हिस्सा क्यों है ? किन परिस्थितियों में आप grep -rlएक ही फ़ाइल नाम का दो बार उत्पादन करने की उम्मीद करेंगे ?
त्रिकाल

5

अन्य समाधान रेगेक्स सिंटैक्स को मिलाते हैं। खोज और प्रतिस्थापन दोनों के लिए पर्ल / पीसीआरई पैटर्न का उपयोग करने के लिए , और केवल मिलान वाली फ़ाइलों को संसाधित करने के लिए, यह काफी अच्छी तरह से काम करता है:

grep -rlZPi 'match1' | xargs -0r perl -pi -e 's/match2/replace/gi;'

जहां match1और match2आमतौर पर समान होते हैं, लेकिन match1अधिक उन्नत सुविधाओं को हटाने के लिए सरलीकृत किया जा सकता है जो केवल प्रतिस्थापन के लिए प्रासंगिक हैं, जैसे समूहों को कैप्चर करना।

अनुवाद: grepपुनरावर्ती और सूची फ़ाइलें जो इस PCRE पैटर्न से मेल खाती हैं, फ़ाइल नाम में किसी विशेष वर्ण की रक्षा के लिए nul द्वारा अलग की जाती हैं, फिर उन फ़ाइलनामों को पाइप करती हैं, xargsजो एक nul- पृथक सूची की अपेक्षा कर रहे हैं, लेकिन यदि कोई नाम प्राप्त नहीं होता है, तो वे कुछ भी नहीं करेंगे। और perlस्थानापन्न रेखाओं पर जाएं जहां मैच पाए जाते हैं।

बाइनरी फ़ाइलों को अनदेखा Iकरने के grepलिए स्विच जोड़ें । केस-संवेदी मिलान के लिए, ड्रॉप iसे स्विच grep, और iझंडा प्रतिस्थापन अभिव्यक्ति से जुड़ी है, लेकिन नहींi स्विच पर perlही।


पर्ल स्वयं एक फ़ाइल संरचना को पुनरावृत्ति करने में काफी सक्षम है। वास्तव में, एक उपकरण है find2perlजो पर्ल के साथ जहाज करता है जो बिना किसी xargsचालबाजी के इस तरह का काम करता है ।
त्रिकाल

@tripleee findफ़ाइल सामग्री नहीं खोजता है, और बिंदु केवल पर्ल प्रोग्राम लिखने के बिना फ़ाइलों के मिलान की प्रक्रिया है।
वॉलफ

यह विंडोज के लिए एक अच्छा समाधान है, क्योंकि यह लाइन-एंडिंग को परिवर्तित करने के सेड-आधारित समाधान के मुद्दे से बचा जाता है। धन्यवाद!
जामहंदी

4

आमतौर पर grep के साथ नहीं, बल्कि sed -i 's/string_to_find/another_string/g'या के साथ perl -i.bak -pe 's/string_to_find/another_string/g'


3

बहुत सावधानी बरतें जब उपयोग करें findऔर sedएक git रेपो में! यदि आप द्विआधारी फ़ाइलों को बाहर नहीं करते हैं तो आप इस त्रुटि को समाप्त कर सकते हैं:

error: bad index file sha1 signature 
fatal: index file corrupt

इस त्रुटि को हल करने के लिए आपको sedअपने new_stringसाथ अपनी जगह बदलकर वापस करना होगा old_string। यह आपके बदले हुए तारों को वापस कर देगा, इसलिए आप समस्या की शुरुआत में वापस आ जाएंगे।

एक स्ट्रिंग की खोज करने और उसे बदलने का सही तरीका है बाइनरी फ़ाइलों को अनदेखा करने के लिए उसे छोड़ना findऔर उसका उपयोग grepकरना:

sed -ri -e "s/old_string/new_string/g" $(grep -Elr --binary-files=without-match "old_string" "/files_dir")

क्रेडिट @hobs के लिए


1

यहां है जो मुझे करना होगा:

find /path/to/dir -type f -iname "*filename*" -print0 | xargs -0 sed -i '/searchstring/s/old/new/g'

इस युक्त सभी फ़ाइलों के लिए दिखेगा filenameतहत फ़ाइल के नाम में /path/to/dir, पाया हर फ़ाइल के लिए की तुलना में, के साथ लाइन के लिए खोज searchstringऔर की जगह oldके साथ new

हालाँकि अगर आप filenameफ़ाइल के नाम में स्ट्रिंग के साथ एक विशिष्ट फ़ाइल की तलाश में चूक करना चाहते हैं , तो बस:

find /path/to/dir -type f -print0 | xargs -0 sed -i '/searchstring/s/old/new/g'

यह ऊपर के समान काम करेगा, लेकिन सभी फाइलों के नीचे पाया जाएगा /path/to/dir


0

एक अन्य विकल्प सिर्फ ग्लोबस्टार के साथ पर्ल का उपयोग करना होगा।

shopt -s globstarआपके .bashrc(या जहां भी) सक्षम करने से **ग्लोब पैटर्न को सभी उप-निर्देशिकाओं और फ़ाइलों के पुनरावर्ती रूप से मिलान करने की अनुमति मिलती है ।

इस प्रकार का उपयोग करने के साथ perl -pXe 's/SEARCH/REPLACE/g' -i **पुनरावर्ती रूप से प्रतिस्थापित SEARCHकिया जाएगा REPLACE

-Xझंडा "सभी चेतावनियों को निष्क्रिय करने के लिए" पर्ल बताता है - जिसका अर्थ है कि यह निर्देशिका के बारे में शिकायत नहीं होंगे।

Globstar भी आप की तरह काम करने के लिए अनुमति देता है sed -i 's/SEARCH/REPLACE/g' **/*.extअगर आप को बदलने के लिए करना चाहता था SEARCHके साथ REPLACEविस्तार के साथ सभी चाइल्ड फाइलों में .ext


"एक अन्य विकल्प ग्लोबस्टार के साथ केवल पर्ल का उपयोग करना होगा ..." - सोलिसिस की तरह पॉज़िक्स मशीनों पर नहीं। यही कारण है कि मैं विशेष रूप से देख रहा हूँ है grepऔर sed
jww
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.