कैसे एक पुनरावर्ती खोजने के लिए / awk या sed के साथ एक स्ट्रिंग की जगह?


674

मैं हर घटना को कैसे ढूँढूँ और प्रतिस्थापित करूँ:

subdomainA.example.com

साथ में

subdomainB.example.com

/home/www/निर्देशिका पाठ के तहत हर पाठ फ़ाइल में पुनरावर्ती?


93
सुझाव: एक svn चेकआउट ट्री में नीचे मत करो ... यह जादू .svn फ़ोल्डर फ़ाइलों को अधिलेखित कर देगा।
जे। पॉल्फ

7
ओह माय गॉड यह वही है जो मैंने अभी किया है। लेकिन यह काम किया और लगता है कि कोई नुकसान नहीं हुआ है। क्या हो सकता है सबसे बुरा?
जे। काटज़विंकल

5
@ जे.कात्ज़्विंकेल: बहुत कम से कम, यह भ्रष्ट चेकसम हो सकता है, जो आपके भंडार को दूषित कर सकता है।
निन्जाएजेको

3
Sed का उपयोग करने वाले सभी लोगों के लिए त्वरित टिप: यह आपकी फ़ाइलों में अनुगामी newlines जोड़ देगा। यदि आप उन्हें नहीं चाहते हैं, तो पहले एक ऐसा खोज-प्रतिस्थापन करें जो किसी भी चीज से मेल नहीं खाएगा, और जो इसे करने के लिए प्रतिबद्ध है। तब असली एक करो। फिर अंतःक्रियात्मक रूप से रिबेट करें और पहले वाले को हटा दें।
फंक

5
आप एक निर्देशिका को छोड़ सकते हैं, जैसे कि git, xargs करने से पहले पाइपिंग -path ./.git -prune -oमें उपयोग करके परिणामों सेfind . -path ./.git -prune -o -type f -name '*matchThisText*' -print0
devinbost

जवाबों:


850
find /home/www \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'

-print0findएक नई रेखा के बजाय एक अशक्त चरित्र द्वारा अलग किए गए परिणामों में से प्रत्येक को प्रिंट करना बताता है। आपकी घटना के नाम पर नई सुर्खियों में आने की संभावना नहीं है, फिर भी यह xargsसही फ़ाइल नाम पर काम करने देता है ।

\( -type d -name .git -prune \)एक अभिव्यक्ति है जो पूरी तरह से नामित सभी निर्देशिकाओं पर छोड़ देता है .git। आप आसानी से इसका विस्तार कर सकते हैं, यदि आप एसवीएन का उपयोग करते हैं या अन्य फ़ोल्डर हैं जिन्हें आप संरक्षित करना चाहते हैं - बस अधिक नामों के खिलाफ मैच करें। यह लगभग बराबर है -not -path .git, लेकिन अधिक कुशल है, क्योंकि निर्देशिका में हर फ़ाइल की जांच करने के बजाय, यह इसे पूरी तरह से छोड़ देता है। इसके -oबाद यह आवश्यक है कि कैसे-prune वास्तव काम करता है।

अधिक जानकारी के लिए, देखें man find


132
OSX पर आपको sed: 1: "...": invalid command code .समस्या का सामना करना पड़ सकता है। ऐसा लगता है कि -i विकल्प विस्तार की उम्मीद करता है और पार्स 's/../...'आदेश देता है। समाधान: पास एक्सटेंशन '' टू -आई विकल्प जैसे sed -i '' 's/...
रॉबर्ट लूजो

6
नोट: यदि आप इसे किसी निर्देशिका में उपयोग करते हैं और आश्चर्य करते हैं कि svn stकोई परिवर्तन क्यों नहीं दिखता है, तो इसका कारण यह है कि आपने .svn निर्देशिकाओं में फ़ाइलें संशोधित की हैं! find . -maxdepth 1 -type f -print0 | xargs -0 sed -i 's/toreplace/replaced/g'इसके बजाय उपयोग करें ।
ACK_stoverflow

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

13
grep -r 'hello' -l --null . | xargs -0 sed -i 's#hello#world#g'असंबंधित फ़ाइलों को संपादित करने से बचने के लिए इसका उपयोग करें (sed फाइल को बदल सकता है)।
caiguanhao

6
"लेकिन इसके बजाय मेरे git इंडेक्स को दूषित कर दिया।" इस बारे में बहुत चिंता न करें कि आप find .git ... | ... 'sed -i s/(the opposite from before)/g'अपने git इंडेक्स को ठीक करने के लिए क्या कर सकते हैं
Massey101

259

नोट : इस कमांड को git रेपो सहित किसी फोल्डर पर न चलाएं - .it में परिवर्तन आपके git इंडेक्स को दूषित कर सकता है।

find /home/www/ -type f -exec \
    sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +

यहां अन्य उत्तरों की तुलना में, यह सबसे सरल है और पर्ल के बजाय sed का उपयोग करता है, जो कि मूल प्रश्न के लिए पूछा गया है।


50
ध्यान दें कि यदि आप BSD sed का उपयोग कर रहे हैं (Mac OS X सहित) तो आपको sed के -iविकल्प के लिए एक स्पष्ट खाली स्ट्रिंग arg देना होगा । अर्थात्: sed -i '' 's/original/replacement/g'
नाथन क्रेक

2
@ जॉन्ज्विनक मेरी गलती, मि + से चूक गई। अजीब तरह से, निकिता का समाधान मेरे लिए तेजी से चलता है।
सैम

6
@AoeAoe: +बहुत कम sedप्रक्रियाओं की संख्या कम है । यह अधिक कुशल है।
जॉन Zwinck

4
मैं git रेपो वाले फ़ोल्डर में इसे सुरक्षित रूप से कैसे कर सकता हूं?
हत्शेपसुत

20
यदि आप अपने खोज परिणामों से रेपो को बाहर करते हैं, तो गिट रेपो वाले फ़ोल्डर पर निष्पादित करना सुरक्षित है find . -not -path '*/\.git*' -type f ...:।
डेल एंडरसन

210

मेरे लिए सबसे सरल तरीका है

grep -rl oldtext . | xargs sed -i 's/oldtext/newtext/g'

1
@ एनाटोली: सिर्फ एक सवाल: मैं बाइनरी फ़ाइलों (निष्पादन योग्य फ़ाइलों) को कैसे बाहर कर सकता हूं ?
2322 बजे user2284570

3
@ user2284570 -Iया --binary-file=without-matchgrep झंडे का उपयोग करें ।
ज़ीचिन

34
यह विशेष रूप से अच्छी तरह से काम करता है, जब आपको निर्देशिकाओं को बाहर करने की आवश्यकता होती है, जैसे कि .svn। उदाहरण के लिए:grep -rl oldtext . --exclude-dir=.svn | xargs sed -i 's/oldtext/newtext/g'
फिएट

11
brew install gnu-sedऔर gsedदर्द की दुनिया से बचने के लिए OSX पर उपयोग करें ।
पी आई

1
लोग कृपया ध्यान दें, यदि आपकी परियोजना का संस्करण है, तो इसके बजाय इसका उपयोग करें git grep -rl oldtext . | xargs sed -i 's/oldtext/newtext/g':। यह सब ठीक नहीं है f * ck अपने .gitdir
पाओलो

61

सभी चाल लगभग समान हैं, लेकिन मुझे यह पसंद है:

find <mydir> -type f -exec sed -i 's/<string1>/<string2>/g' {} +
  • find <mydir>: निर्देशिका में देखो।

  • -type f:

    फ़ाइल प्रकार की है: नियमित फ़ाइल

  • -exec command {} +:

    -Exec कार्रवाई का यह संस्करण चयनित फ़ाइलों पर निर्दिष्ट कमांड चलाता है, लेकिन कमांड लाइन अंत में प्रत्येक चयनित फ़ाइल नाम को जोड़कर बनाया गया है; कमांड की कुल संख्या का मिलान की गई फ़ाइलों की संख्या से बहुत कम होगा। कमांड लाइन को उसी तरह से बनाया गया है जिस तरह से xargs अपनी कमांड लाइन बनाता है। कमांड के भीतर केवल `{} का एक उदाहरण दिया जाता है। कमांड को शुरुआती डायरेक्टरी में निष्पादित किया जाता है।


@ user2284570 -exec के साथ? उपकरण नाम के बजाय निष्पादन योग्य पर पथ सेट करने का प्रयास करें।
11:15 बजे I159

@ I159: नहीं: निष्पादन योग्य बायनेरिज़ को छोड़ दें (लेकिन शेल स्क्रिप्ट शामिल करें)
user2284570

8
@ I159 क्या यह जवाब जॉन ज़िनक के समान नहीं है ?
मोनिका कृपया

1
@ user2284570 "बाइनरी फ़ाइल" की अवधारणा पूरी तरह से परिभाषित नहीं है। आप fileप्रत्येक फ़ाइल के प्रकार को निर्धारित करने की कोशिश करने के लिए कमांड का उपयोग कर सकते हैं , लेकिन इसके आउटपुट में बेतरतीब विविधताएं थोड़ी भयावह हो सकती हैं। -I(उर्फ --mime) विकल्प कुछ हद तक मदद करता है, या --mime-typeआपको लगता है कि है। इस साफ-सुथरे वन-लाइनर को कैसे ठीक किया जाए, यह इस छोटे से कमेंट बॉक्स के लिए अफसोस की बात है। शायद एक अलग प्रश्न पोस्ट करें यदि आपको सहायता की आवश्यकता है? (हो सकता है कि तब यहां एक लिंक के साथ एक टिप्पणी जोड़ें।)
ट्रिपल

1
सबसे साफ जवाब! धन्यवाद दोस्त
जुकरोक

39
cd /home/www && find . -type f -print0 |
  xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'

2
मैं उत्सुक हूँ, वहाँ का उपयोग करने के लिए एक कारण है -print0और xargsबजाय -execया -execdir?
फिलिप

4
वहाँ है: "आदमी खोज" से: निर्दिष्ट आदेश प्रत्येक मिलान की गई फ़ाइल के लिए एक बार चलाया जाता है। यही है, अगर / / घर / www में 2000 फाइलें हैं, तो 'खोज ... -एक्सईक ...' के परिणामस्वरूप पर्ल के 2000 चालान होंगे; जबकि 'खोजो ... | xargs ... 'केवल एक या दो बार perl आह्वान करेगा (लगभग 32K का ARG_MAX और औसत फ़ाइल नाम 20 की लंबाई)।
रूसी

2
@Employed रूसी: यही कारण है कि आप उपयोग करेंगे find -exec command {} +- यह xargs की तरह कमांड के अत्यधिक इनवॉइस से बचता है , लेकिन अलग प्रक्रिया के बिना।
जॉन ज़्विनक

2
किस प्लेटफार्म पर? Xargs समाधान पोर्टेबल है, "find ..." -exec "के" मैजिक "इनवॉइस जो प्रत्येक फ़ाइल के लिए सबप्रोसेस प्राप्त नहीं करते हैं जो नहीं मिली हैं।
रूसी

4
@EmployedRingu, find -exec ... {} +2006 से POSIX- निर्दिष्ट किया गया है।
चार्ल्स डफी

34

मेरे लिए याद रखने का सबसे आसान उपाय है https://stackoverflow.com/a/2113224/565525 , अर्थात:

sed -i '' -e 's/subdomainA/subdomainB/g' $(find /home/www/ -type f)

नोट : -i ''OSX समस्या हल करती हैsed: 1: "...": invalid command code .

नोट : यदि आपको प्राप्त करने के लिए बहुत सारी फाइलें हैं Argument list too long। वर्कअराउंड - ऊपर वर्णित उपयोग find -execया xargsसमाधान।


4
workaroundसभी मामलों में पसंदीदा वाक्य रचना होना चाहिए।
मोनिका कृपया

1
कमांड प्रतिस्थापन के साथ समस्या यह $(find...)है कि शेल में व्हॉट्सएप या अन्य शेल मेटाचैकर के साथ फ़ाइल नामों को संभालने का कोई तरीका नहीं है। यदि आप जानते हैं कि यह कोई समस्या नहीं है, तो यह दृष्टिकोण ठीक है; लेकिन हमारे पास कई सवाल हैं, जहां लोगों को इस मुद्दे के बारे में चेतावनी नहीं दी गई थी, या चेतावनी को नहीं समझा।
ट्रिपल

30

चांदी खोजक का उपयोग करने वाले किसी के लिए ( ag)

ag SearchString -l0 | xargs -0 sed -i 's/SearchString/Replacement/g'

चूँकि ag डिफ़ॉल्ट रूप से git / hg / svn फ़ाइल / फ़ोल्डरों को अनदेखा करता है, इसलिए यह भंडार के अंदर चलाने के लिए सुरक्षित है।


16

एक अतिरिक्त के रूप में एक अच्छा oneliner। Git grep का उपयोग करना।

git grep -lz 'subdomainA.example.com' | xargs -0 perl -i'' -pE "s/subdomainA.example.com/subdomainB.example.com/g"

3
अच्छा विचार है अगर आप एक git रेपो के अंदर काम कर रहे हैं क्योंकि आप ओवर राइटिंग का जोखिम नहीं उठाते हैं। / सामग्री (जैसा कि किसी अन्य उत्तर में टिप्पणियों में बताया गया है)।
Mahemoff

1
धन्यवाद, मैं इसे एक बश फ़ंक्शन refactor() { echo "Replacing $1 by $2 in all files in this git repository." git grep -lz $1| xargs -0 perl -i'' -pE "s/$1/$2/g" }उपयोग के रूप में उपयोग करता हूं , उदाहरण के लिए 'शब्द' को 'तलवार' से बदलने के लिए: refactor word swordफिर यह सत्यापित करें कि इसके साथ क्या हुआ git diff
पॉल रौजीक्स

16

के sedमाध्यम से पुनरावृत्ति करने के लिए फ़ाइलों पर कटौती करने के लिए , आप grepअपने स्ट्रिंग उदाहरण के लिए कर सकते हैं :

grep -rl <oldstring> /path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g

यदि आप चलाते हैं man grepतो आप नोटिस करेंगे कि आप एक परिभाषित भी कर सकते हैं--exlude-dir="*.git" झंडे यदि आप .it निर्देशिकाओं को खोजना छोड़ना चाहते हैं, तो git index के मुद्दों से बचना चाहिए क्योंकि अन्य लोगों ने विनम्रता से बताया है।

आपको अग्रणी:

grep -rl --exclude-dir="*.git" <oldstring> /path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g

13

यह एक git रिपॉजिटरी के साथ संगत है, और थोड़ा सरल है:

लिनक्स:

git grep -l 'original_text' | xargs sed -i 's/original_text/new_text/g'

मैक:

git grep -l 'original_text' | xargs sed -i '' -e 's/original_text/new_text/g'

(के लिए धन्यवाद http://blog.jasonmeridth.com/posts/use-git-grep-to-replace-strings-in-files-in-your-git-repository/ )


समझदार उपयोग करने के लिए git-grepकी -zसाथ साथ विकल्प xargs -0
गनीउर_ग्निउरफ

git grepस्पष्ट रूप से केवल एक gitरेपो में समझ में आता है । सामान्य प्रतिस्थापन होगा grep -r
ट्रिपल

@gniourf_gniourf क्या आप समझा सकते हैं?
पेट्र पेलर

2
@PetrPeller: के साथ -z, git-grepउत्पादन क्षेत्रों को अलग-अलग कर देगा नई बाइट्स के बजाय null बाइट्स; और -0, xargsरिक्त बाइट के बजाय रिक्त बाइट्स द्वारा अलग किए गए इनपुट को पढ़ेगा (और उद्धरण के साथ अजीब सामान नहीं)। तो अगर आप को तोड़ने के लिए आदेश नहीं चाहते हैं तो फ़ाइल नाम रिक्त स्थान, उद्धरण या अन्य अजीब वर्ण होने चाहिए, आदेश है: git grep -z -l 'original_text' | xargs -0 sed ...
ग्नौरफ_गनीउरफ

10
find /home/www/ -type f -exec perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +

find /home/www/ -type f सभी फाइलों को / home / www / (और इसके उपनिर्देशिका) में सूचीबद्ध करेगा। "-Exec" ध्वज बताता है कि प्रत्येक फ़ाइल में निम्नलिखित कमांड को चलाना है।

perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +

फाइलों पर कमांड रन होता है (एक बार में कई)। {}फ़ाइल नामों से बदल जाता है। +आदेश के अंत में बताता है findकई फ़ाइल नामों के लिए एक आदेश बनाने के लिए।

प्रति findआदमी पृष्ठ: "कमांड लाइन उसी तरह से बनाई गई है जैसे कि xargs अपनी कमांड लाइन बनाता है।"

इस प्रकार यह उपयोग किए बिना अपने लक्ष्य (और संभाल रिक्त स्थान युक्त फ़ाइल नाम) को प्राप्त करना संभव है xargs -0, या -print0


8

मुझे बस इसकी जरूरत थी और उपलब्ध उदाहरणों की गति से खुश नहीं था। तो मैं अपने साथ आया:

cd /var/www && ack-grep -l --print0 subdomainA.example.com | xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'

प्रासंगिक फाइलों को खोजने के लिए Ack-grep बहुत कुशल है। इस आदेश ने ~ 145 000 फ़ाइलों को एक हवा के साथ बदल दिया, जबकि अन्य को इतना समय लगा कि मैं तब तक इंतजार नहीं कर सका जब तक कि वे खत्म नहीं हो जाते।


अच्छा है, लेकिन grep -ril 'subdomainA' *कहीं नहीं के रूप में उपवास के रूप में है grep -Hr 'subdomainA' * | cut -d: -f1
त्रुष्टक

@ हेनो: सिर्फ एक सवाल: मैं बाइनरी फाइलें (निष्पादन योग्य फाइलें) कैसे बाहर कर सकता हूं ?
user2284570

ack-grep जो आपके लिए स्वचालित रूप से करता है।
हेन्नो

@ हेनो: क्या इसमें शेल स्क्रिप्ट शामिल हैं?
user2284570

हाँ। यहाँ फ़ाइल प्रकारों की एक पूरी सूची है जो इसका समर्थन करता है: परेग्रेप.com
Henno

6

यदि आपको निर्देशिकाओं को बाहर करने की आवश्यकता है तो एक सीधे आगे की विधि ( --exclude-dir=.svn) और रिक्त स्थान के साथ फ़ाइल नाम भी हो सकते हैं (0Byte के साथ grep -Zऔरxargs -0

grep -rlZ oldtext . --exclude-dir=.svn | xargs -0 sed -i 's/oldtext/newtext/g'

6

बदलने का सबसे सरल तरीका ( सभी फाइलें, निर्देशिका, पुनरावर्ती )

find . -type f -not -path '*/\.*' -exec sed -i 's/foo/bar/g' {} +

नोट: कभी-कभी आपको कुछ छिपी हुई फ़ाइलों को अनदेखा करने की आवश्यकता हो सकती है .git, आप ऊपर दिए गए आदेश का उपयोग कर सकते हैं।

यदि आप छुपी हुई फ़ाइलों का उपयोग शामिल करना चाहते हैं,

find . -type f  -exec sed -i 's/foo/bar/g' {} +

दोनों ही स्थिति में स्ट्रिंग fooको नए स्ट्रिंग के साथ बदल दिया जाएगाbar


5

grep -lr 'subdomainA.example.com' | while read file; do sed -i "s/subdomainA.example.com/subdomainB.example.com/g" "$file"; done

मुझे लगता है कि ज्यादातर लोग यह नहीं जानते हैं कि वे "फ़ाइल पढ़ते समय" में कुछ पाइप कर सकते हैं और यह उन बुरा-प्रिंट0 आर्ग्स से बचता है, जबकि फ़ाइलनामों में रिक्त स्थान की भविष्यवाणी करता है।

आगे echoसे पहले सेड जोड़ना आपको यह देखने की अनुमति देता है कि वास्तव में ऐसा करने से पहले क्या फाइलें बदल जाएंगी।


कारण -print0यह है कि यह मामलों को संभालती है उपयोगी है है while readएक नई पंक्ति, एक यूनिक्स फ़ाइल के नाम में मान्य वर्ण नहीं है तो अपने कोड पूरी तरह से मजबूत होने के लिए, यह इस तरह फ़ाइल नाम से निपटने के लिए की जरूरत है, बहुत - बस नहीं संभाल सकते हैं। (इसके अलावा, आप read -rकुछ pesky POSIX विरासत व्यवहार से बचना चाहते हैं read।)
ट्रिपल

इसके अलावा, sedअगर कोई मैच नहीं है तो एक नो-ऑप है, इसलिए grepवास्तव में आवश्यक नहीं है; हालाँकि यह उन फ़ाइलों को फिर से लिखने से बचने के लिए एक उपयोगी अनुकूलन है, जिनमें कोई मेल नहीं है, यदि आपके पास बहुत सारे हैं, या अनावश्यक रूप से फ़ाइलों पर दिनांक टिकटों को अपडेट करने से बचना चाहते हैं।
ट्रिपलए

5

आप इसे नीचे हल करने के लिए awk का उपयोग कर सकते हैं,

for file in `find /home/www -type f`
do
   awk '{gsub(/subdomainA.example.com/,"subdomainB.example.com"); print $0;}' $file > ./tempFile && mv ./tempFile $file;
done

आशा है कि यह आपकी मदद करेगा !!!


मैकओ पर काम करता है किसी भी समस्याओं का सामना! सभी sedआधारित आदेश विफल हो गए जब बायनेरिज़ को ओएक्सएक्स विशिष्ट सेटिंग्स के साथ भी शामिल किया गया था।
Jankapunkt

सावधान ... यह किसी भी फाइल findरिटर्न के उनके नाम में एक स्थान है अगर यह उड़ा देगा ! यह उपयोग करने के लिए अधिक सुरक्षित है while read: stackoverflow.com/a/9612560/1938956
सोरेन Bjornstad

4

इसे इस्तेमाल करे:

sed -i 's/subdomainA/subdomainB/g' `grep -ril 'subdomainA' *`

1
हाय @RikHic, अच्छा टिप - कुछ इस तरह के बारे में सोच रहा था; दुर्भाग्य से ऊपर प्रारूपण सही नहीं निकला :) तो मैं एक पूर्व टैग (काम नहीं करता है) के साथ कोशिश करूँगा - तो पीछे से बचने के साथ: sed -i 's/subdomainA/subdomainB/g'` grep -ril 'subdomainA' /home/www/*` - यह अभी भी बहुत अच्छा नहीं दिखता है, लेकिन चाहिए जीवित बचने के :) :) चीयर्स!
सदाऊ

4
#!/usr/local/bin/bash -x

find * /home/www -type f | while read files
do

sedtest=$(sed -n '/^/,/$/p' "${files}" | sed -n '/subdomainA/p')

    if [ "${sedtest}" ]
    then
    sed s'/subdomainA/subdomainB/'g "${files}" > "${files}".tmp
    mv "${files}".tmp "${files}"
    fi

done

4

इस ब्लॉग पोस्ट के अनुसार :

find . -type f | xargs perl -pi -e 's/oldtext/newtext/g;'

आप स्लैश से कैसे बचेंगे /? : उदाहरण के लिए, मैं आई पी पतों को बदलना चाहते हैं xxx.xxx.xxx.xxxके लिएxxx.xxx.xxx.xxx/folder
पत्रोस

आप /with \ के साथ बच सकते हैं । उदाहरण के लिए:find . -type f | xargs perl -pi -e 's/xxx.xxx.xxx.xxx\/folder/newtext/g;'
J.Hpour

3

यदि आप vimएक साथ grepया findटूल के साथ उपयोग करने में कोई आपत्ति नहीं करते हैं , तो आप इस लिंक में उपयोगकर्ता गर्ट द्वारा दिए गए उत्तर का अनुसरण कर सकते हैं -> एक बड़े फ़ोल्डर पदानुक्रम में पाठ प्रतिस्थापन कैसे करें?

यहाँ सौदा है:

  • पुनरावर्ती grep स्ट्रिंग के लिए जिसे आप एक निश्चित पथ में बदलना चाहते हैं, और मिलान फ़ाइल का केवल पूरा पथ लें। (यह होगा $(grep 'string' 'pathname' -Rl)

  • (वैकल्पिक) यदि आप केंद्रीयकृत निर्देशिका पर उन फ़ाइलों का पूर्व-बैकअप बनाना चाहते हैं, तो शायद आप इसका उपयोग भी कर सकते हैं: cp -iv $(grep 'string' 'pathname' -Rl) 'centralized-directory-pathname'

  • उसके बाद आप vimदिए गए लिंक पर दी गई योजना के समान एक योजना का पालन कर सकते हैं / बदल सकते हैं :

    • :bufdo %s#string#replacement#gc | update

2

थोड़ा पुराना स्कूल लेकिन इसने OS X पर काम किया।

कुछ तरकीबें हैं:

• केवल .slsवर्तमान निर्देशिका के तहत विस्तार के साथ फ़ाइलों को संपादित करेगा

.यह सुनिश्चित करने के लिए बच जाना चाहिए कि sedउन्हें "किसी भी चरित्र" के रूप में मूल्यांकन नहीं करना चाहिए

• सामान्य के बजाय परिसीमाक के ,रूप में प्रयोग किया जाता हैsed/

यह भी ध्यान दें कि यह एक variableके पथ में एक पास करने के लिए एक जिन्जा टेम्पलेट को संपादित करना है import(लेकिन यह विषय से दूर है)।

सबसे पहले, अपने sed कमांड को सत्यापित करें कि आप क्या चाहते हैं (यह केवल स्टडआउट में परिवर्तन प्रिंट करेगा, यह फ़ाइलों को नहीं बदलेगा):

for file in $(find . -name *.sls -type f); do echo -e "\n$file: "; sed 's,foo\.bar,foo/bar/\"+baz+\"/,g' $file; done

एक बार जब आप परिवर्तन करने के लिए तैयार हों, तो आवश्यकतानुसार कमांड को संपादित करें:

for file in $(find . -name *.sls -type f); do echo -e "\n$file: "; sed -i '' 's,foo\.bar,foo/bar/\"+baz+\"/,g' $file; done

Sed कमांड -i ''में ध्यान दें , मैं मूल फ़ाइलों का बैकअप नहीं बनाना चाहता था (जैसा कि OS X पर sed के साथ इन-प्लेस एडिट्स में बताया गया है या इस पेज में रॉबर्ट लुजो की टिप्पणी में)।

हैप्पी seding लोग!


2

सिर्फ बदलाव से बचने के लिए

  • NearlysubdomainA.example.com
  • subdomainA.example.comp.other

फिर भी

  • subdomainA.example.com.IsIt.good

(शायद डोमेन रूट के पीछे के विचार में अच्छा नहीं है)

find /home/www/ -type f -exec sed -i 's/\bsubdomainA\.example\.com\b/\1subdomainB.example.com\2/g' {} \;

2

मैं सिर्फ टॉप का उपयोग करता हूं:

find . -name '*.[c|cc|cp|cpp|m|mm|h]' -print0 |  xargs -0 tops -verbose  replace "verify_noerr(<b args>)" with "__Verify_noErr(<args>)" \
replace "check(<b args>)" with "__Check(<args>)" 

प्लस वन के लिए `* *। [c | cc | cp | cpp | m | mm | h] '`
FractalSpace

2

यहां एक ऐसा संस्करण है जो सबसे अधिक सामान्य होना चाहिए; उदाहरण के लिए find( duइसके बजाय) का उपयोग करने की आवश्यकता नहीं है । इसके लिए आवश्यकता होती है xargs, जो केवल प्लान 9 (जैसे 9फ्रंट) के कुछ संस्करणों में पाए जाते हैं।

 du -a | awk -F' '  '{ print $2 }' | xargs sed -i -e 's/subdomainA\.example\.com/subdomainB.example.com/g'

यदि आप फ़ाइल एक्सटेंशन जैसे फ़िल्टर जोड़ना चाहते हैं तो उपयोग करें grep:

 du -a | grep "\.scala$" | awk -F' '  '{ print $2 }' | xargs sed -i -e 's/subdomainA\.example\.com/subdomainB.example.com/g'

1

IBMi पर Qshell (qsh) के लिए, OP द्वारा टैग नहीं किया गया है।

क्ष आदेशों की सीमाएँ:

  • ढूँढें -print0 विकल्प नहीं है
  • xargs में -0 विकल्प नहीं है
  • sed में -i विकल्प नहीं है

इस प्रकार क्ष में समाधान:

    PATH='your/path/here'
    SEARCH=\'subdomainA.example.com\'
    REPLACE=\'subdomainB.example.com\'

    for file in $( find ${PATH} -P -type f ); do

            TEMP_FILE=${file}.${RANDOM}.temp_file

            if [ ! -e ${TEMP_FILE} ]; then
                    touch -C 819 ${TEMP_FILE}

                    sed -e 's/'$SEARCH'/'$REPLACE'/g' \
                    < ${file} > ${TEMP_FILE}

                    mv ${TEMP_FILE} ${file}
            fi
    done

चेतावनियां:

  • समाधान त्रुटि से निपटने को बाहर करता है
  • ओपी द्वारा टैग नहीं किया गया

यह कुछ pesky मुद्दों को उद्धृत करने के साथ-साथ पढ़ने वाली पंक्तियों के साथ है for
तिहरा

1

यदि आप अपने एसवीएन रिपॉजिटरी को पूरी तरह से नष्ट किए बिना इसका उपयोग करना चाहते हैं, तो आप सभी छिपी हुई फ़ाइलों को अनदेखा करके 'खोज' बता सकते हैं:

find . \( ! -regex '.*/\..*' \) -type f -print0 | xargs -0 sed -i 's/subdomainA.example.com/subdomainB.example.com/g'

कोष्ठक सतही प्रतीत होते हैं। इससे पहले इसमें एक स्वरूपण त्रुटि थी जिसने इसे अनुपयोगी बना दिया (मार्कडाउन रेंडरिंग रेगेक्स के कुछ पात्रों को खा जाएगा)।
ट्रिपलए

1

के संयोजन का उपयोग करना grepऔरsed

for pp in $(grep -Rl looking_for_string)
do
    sed -i 's/looking_for_string/something_other/g' "${pp}"
done

@tripleee मैंने इसे थोड़ा संशोधित किया। इस स्थिति में आउटपुट के लिए कमांड grep -Rl patternफाइल की सूची जहां पैटर्न है। फाइलें forलूप में नहीं पढ़ी जाती हैं ।
पावेल

है ना? आपके पास अभी भी एक forलूप है; यदि किसी लौटे फ़ाइल नाम में व्हॉट्सएप है, तो यह सही ढंग से काम नहीं करेगा, क्योंकि शेल forतर्क सूची को टोकन करता है। लेकिन फिर आप लूप के अंदर बिना कोट्स के फाइल नेम वेरिएबल का इस्तेमाल करते हैं, इसलिए अगर आपने इसे ठीक कर दिया तो यह वहां टूट जाएगा। इन बचे हुए कीड़ों को ठीक करने से आप @ MadMan2064 के उत्तर के समान बन जाएंगे।
ट्रिपल एफ

@tripleee हाँ, यह सच है, मुझे यह याद आया।
पावेल

1

एक गैट भंडार में सभी घटनाओं को बदलने के लिए आप इसका उपयोग कर सकते हैं:

git ls-files -z | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'

स्थानीय गिट रेपो में सूची फ़ाइलें देखें ? अन्य विकल्पों के लिए एक रिपॉजिटरी में सभी फाइलों को सूचीबद्ध करने के लिए। -zविकल्प Git बताता है एक शून्य बाइट, जो भरोसा दिलाते हैं कि साथ फ़ाइल नाम को अलग करने के xargs(विकल्प के साथ -0) फ़ाइल नाम अलग कर सकते हैं, भले ही वे रिक्त स्थान या whatnot होते हैं।


1
perl -p -i -e 's/oldthing/new_thingy/g' `grep -ril oldthing *`

1
उपयोग नहीं awk/ sed, लेकिन पर्ल सामान्य है (केवल व्यस्त बॉक्स के साथ एम्बेडेड / सिस्टम को छोड़कर)।
पाविक

1

कई फ़ाइलों को बदलने के लिए (और एक बैकअप को बचाने के रूप में *.bak):

perl -p -i -e "s/\|/x/g" *

निर्देशिका में सभी फ़ाइलों को ले जाएगा और |x के साथ एक "पर्ल पाई" (एक पाई के रूप में आसान) कहा जाता है


हालांकि निर्देशिका के माध्यम से पुनरावर्ती नहीं।
PKHunter

इसे पाइप करना संभव है, जो निर्देशिकाओं के माध्यम से इसे बहुत ही समायोज्य बनाता है। josephscott.org/archives/2005/08/… और unix.stackexchange.com/questions/101415/…
Stenemo
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.