पहले मैच के बाद sed का उपयोग करके लाइन डालें


245

किसी कारण से मुझे इसका सीधा-सा जवाब नहीं मिल रहा है और मैं इस समय थोड़े क्रंच पर हूं। मैं sedकमांड का उपयोग करके एक विशिष्ट स्ट्रिंग से मेल खाने वाली पहली पंक्ति के बाद टेक्स्ट की पसंद लाइन डालने के बारे में कैसे जाऊंगा । मेरे पास है ...

CLIENTSCRIPT="foo"
CLIENTFILE="bar"

और मैं एक लाइन सम्मिलित करना चाहता हूँ CLIENTSCRIPT=जिसके परिणामस्वरूप लाइन ...

CLIENTSCRIPT="foo"
CLIENTSCRIPT2="hello"
CLIENTFILE="bar"

जवाबों:


379

GNU sed का उपयोग करके ऐसा करने का प्रयास करें:

sed '/CLIENTSCRIPT="foo"/a CLIENTSCRIPT2="hello"' file

यदि आप इन-प्लेस का उपयोग करना चाहते हैं , तो उपयोग करें

sed -i '/CLIENTSCRIPT="foo"/a CLIENTSCRIPT2="hello"' file

उत्पादन

CLIENTSCRIPT="foo"
CLIENTSCRIPT2="hello"
CLIENTFILE="bar"

डॉक्टर


धन्यवाद! और फ़ाइल की सामग्री को मुद्रित किए बिना फ़ाइल पर वापस लिखने के लिए इसे प्राप्त करने के लिए?
user2150250

11
ध्यान दें कि दोनों GNU मानते हैं sed। यह मानक sedवाक्यविन्यास नहीं है और किसी अन्य sedकार्यान्वयन के साथ काम नहीं करेगा ।
स्टीफन चेजेलस

मुझे मेरे लिए काम करने में परेशानी हो रही थी क्योंकि मैं एक अलग परिसीमन का उपयोग कर रहा था। RTFM'ing के बाद, मैंने महसूस किया कि मुझे regex को a से शुरू करना था, फिर सीमांकक।
क्रिस्टी

10
यह केवल पहले मैच के लिए कैसे लागू होता है? यह स्पष्ट है कि यह मैच के बाद पाठ को जोड़ता है, लेकिन यह केवल पहले मैच को कैसे जानता है?
बजे मोहम्मद नौरेल्डिन

7
यह मेरे लिए हर मैच के बाद पाठ जोड़ता है।
schoppenhauer

49

मानक sedसिंटैक्स पर ध्यान दें (जैसे कि POSIX में, इसलिए सभी अनुरूप sedकार्यान्वयनों द्वारा समर्थित (GNU, OS / X, BSD, Solaris ...)):

sed '/CLIENTSCRIPT=/a\
CLIENTSCRIPT2="hello"' file

या एक लाइन पर:

sed -e '/CLIENTSCRIPT=/a\' -e 'CLIENTSCRIPT2="hello"' file

( -expressions (और -files की सामग्री ) sed स्क्रिप्ट की sedव्याख्या करने के लिए नए सिरे से जुड़ती है )।

-iयथा-स्थान संपादन के लिए विकल्प भी एक जीएनयू विस्तार, कुछ अन्य कार्यान्वयन का समर्थन (FreeBSD की तरह) है -i ''कि के लिए।

वैकल्पिक रूप से, पोर्टेबिलिटी के लिए, आप perlइसके बजाय उपयोग कर सकते हैं :

perl -pi -e '$_ .= qq(CLIENTSCRIPT2="hello"\n) if /CLIENTSCRIPT=/' file

या आप उपयोग कर सकते हैं edया ex:

printf '%s\n' /CLIENTSCRIPT=/a 'CLIENTSCRIPT2="hello"' . w q | ex -s file

2
मैं गलत हो सकता हूं, लेकिन वर्तमान sed -e '/CLIENTSCRIPT=/a\' -e 'CLIENTSCRIPT2="hello"' fileपहले पैरामीटर के अंत में बोली से बच जाता है और कमांड को तोड़ देता है।
गाड़ी

1
@AndonedCart, बॉर्न, cshया rcपरिवार के गोले में , '...'मजबूत उद्धरण हैं जिनके अंदर बैकस्लैश विशेष नहीं है। एकमात्र अपवाद जो मुझे पता है वह fishशेल है।
स्टीफन चेजेलस

1
मैकओएस पर टर्मिनल (और बाद में टर्मिनल में एक स्क्रिप्ट रन) भी एक अपवाद है, जाहिरा तौर पर। मुझे वैकल्पिक वाक्यविन्यास मिला, लेकिन फिर भी धन्यवाद।
कार्ट गाड़ी

1
@AndonedCart, यह कुछ और है। यही कारण है कि MacOS है sedनहीं POSIX यहाँ संगत किया जा रहा है। यह मेरे बयान के बारे में बताता है कि यह गलत है (एक पंक्ति संस्करण के लिए) पोर्टेबल है। यदि यह वास्तव में एक गैर-अनुरूपता है या मेरी ओर से मानक की गलत व्याख्या है, तो मैं पुष्टि के लिए opengroup पूछूंगा।
स्टीफन चेजेलस

19

एक POSIX sआज्ञा का पालन करते हुए अनुपालन करता है :

sed '/CLIENTSCRIPT="foo"/s/.*/&\
CLIENTSCRIPT2="hello"/' file

1
... वह भी नई लाइनें डालने का समर्थन करता है। मुझे यह पसंद है!
Stephan Henningsen

1
यह भी देखें sed -e '/.../s/$/\' -e 'CLI.../'कि जो लाइनों के साथ समस्याओं से बचते हैं उनमें बाइट अनुक्रम होते हैं जो वैध वर्ण नहीं बनाते हैं।
स्टीफन चेजेलस

14

मैडओएस (कम से कम, ओएस 10) और यूनिक्स एक जैसे (यानी। गिल्स सीड की आवश्यकता नहीं है जैसे कि गिल्स '(वर्तमान में स्वीकृत) एक करता है)

sed -e '/CLIENTSCRIPT="foo"/a\'$'\n''CLIENTSCRIPT2="hello"' file

यह बाश में काम करता है और शायद अन्य गोले भी हैं जो $ '\ n' मूल्यांकन बोली शैली को जानते हैं। सब कुछ एक लाइन पर हो सकता है और पुराने / POSIX sed कमांड में काम कर सकता है। यदि CLIENTSCRIPT = "foo" (या आपके समतुल्य) से मेल खाते कई पंक्तियाँ हो सकती हैं और आप पहली बार केवल अतिरिक्त पंक्ति जोड़ना चाहते हैं, तो आप इसे निम्नानुसार फिर से काम कर सकते हैं:

sed -e '/^ *CLIENTSCRIPT="foo"/b ins' -e b -e ':ins' -e 'a\'$'\n''CLIENTSCRIPT2="hello"' -e ': done' -e 'n;b done' file

(यह लाइन सम्मिलन कोड के बाद एक लूप बनाता है जो बाकी फाइल के माध्यम से साइकिल करता है, फिर कभी पहले सेड कमांड पर वापस नहीं आता है)।

आप देख सकते हैं कि मैंने मैच पैटर्न में एक '^ *' जोड़ा है कि लाइन किसी टिप्पणी में दिखाई देती है, कहती है या इंडेंट की जाती है। इसकी 100% परिपूर्ण नहीं है, लेकिन कुछ अन्य स्थितियों के आम होने की संभावना है। आवश्यकतानुसार समायोजित करें ...

इन दो समाधानों को भी समस्या का दौर मिलता है (एक पंक्ति को जोड़ने के लिए जेनेरिक समाधान के लिए) कि अगर आपकी नई सम्मिलित लाइन में अनसैप्ड बैकस्लैश या एम्परसेंड्स हैं, तो उन्हें sed द्वारा समझा जाएगा और संभवत: उसी तरह बाहर नहीं आएगा, जैसे कि \n- जैसे। \0पहली पंक्ति का मिलान होगा। विशेष रूप से आसान है अगर आप एक ऐसी लाइन जोड़ रहे हैं जो एक वैरिएबल से आती है जहां आपको अन्यथा $ {var //} से पहले या सब सेडान आदि का उपयोग करके सब कुछ से बचना होगा।

यह समाधान लिपियों में थोड़ा कम गन्दा है (हालांकि उद्धृत करना और पढ़ना आसान नहीं है) हालांकि, जब आप कमांड के लिए रिप्लेसमेंट टेक्स्ट को एक पंक्ति के शुरू में नहीं रखना चाहते हैं, तो फ़ंक्शन में इंडेंटेड लाइनों के साथ। मैंने यह लाभ उठाया है कि शेल के द्वारा $ '\ n' का मूल्यांकन किया जाता है, इसके नियमित '\ _' एकल-उद्धरण मूल्यों में नहीं।

यह लंबे समय से पर्याप्त हो रहा है कि मुझे लगता है कि perl / यहां तक ​​कि awk अधिक पठनीय होने के कारण जीत सकता है।


1
जवाब के लिए धन्यवाद! पहले AIX OS पर एक आकर्षण की तरह काम करता है।
अभिषेक

आप यह कैसे करते हैं, लेकिन बहु-पंक्ति सम्मिलन के लिए
त्सु

1
यदि आप उन्हें एक बैकस्लैश ( स्रोत ) से "बच "ते हैं, तो पॉसिक्स सेड, प्रतिस्थापन स्ट्रिंग में शाब्दिक नईलाइन्स का समर्थन करता है । तो: s/CLIENTSCRIPT="foo"/&\ [दर्ज करें] CLIENTSCRIPT2="hello"/ । बैकस्लैश को लाइन पर बहुत अंतिम चरित्र होना चाहिए (इसके बाद कोई व्हाट्सएप नहीं), इस टिप्पणी में यह कैसे दिखता है, इसके विपरीत।
TheDudeAbides

1
@tatsu के प्रतिस्थापन स्ट्रिंग में न्यूलाइन्स s///, साथ ही साथ aऔर iकमांड में उन लोगों को "बच कर" निकाला जा सकता है, जो मैं अपनी टिप्पणी में वर्णित उसी विधि का उपयोग कर रहा हूं।
TheDudeAbides

4

शायद इसके लिए एक उत्तर पोस्ट करने में थोड़ी देर हो गई, लेकिन मैंने उपरोक्त कुछ समाधानों को थोड़ा बोझिल पाया।

मैंने सेड में सरल स्ट्रिंग प्रतिस्थापन की कोशिश की और यह काम किया:

sed 's/CLIENTSCRIPT="foo"/&\nCLIENTSCRIPT2="hello"/' file

& हस्ताक्षर मिलान स्ट्रिंग को दर्शाता है, और फिर आप \ n और नई पंक्ति जोड़ते हैं।

जैसा कि उल्लेख है, यदि आप इसे जगह में करना चाहते हैं:

sed -i 's/CLIENTSCRIPT="foo"/&\nCLIENTSCRIPT2="hello"/' file

एक और बात। आप एक अभिव्यक्ति का उपयोग करके मेल कर सकते हैं:

sed -i 's/CLIENTSCRIPT=.*/&\nCLIENTSCRIPT2="hello"/' file

आशा है कि यह किसी की मदद करता है


यह लिनक्स पर ठीक काम करता है, जहां GNU sed डिफ़ॉल्ट है, क्योंकि यह \nप्रतिस्थापन स्ट्रिंग में समझता है। सादा-वेनिला (इसे POSIX) sedकरता नहीं समझते हैं \nप्रतिस्थापन स्ट्रिंग में, हालांकि, तो यह बीएसडी या MacOS-जब तक आप स्थापित किया है जीएनयू किसी भी तरह sed पर नहीं होगा काम। वेनिला सेड के साथ आप उन्हें "बचकर" - कि एक बैकस्लैश के साथ लाइन को समाप्त करके, फिर [एंटर] ( संदर्भ , शीर्षक के लिए ) दबाकर नए सिरे से एम्बेड कर सकते हैं । इसका मतलब है कि आपके sed कमांड को टर्मिनल में कई लाइनों को फैलाना है। [2addr]s/BRE/replacement/flags
TheDudeAbides

प्रतिस्थापन स्ट्रिंग में शाब्दिक न्यूलाइन प्राप्त करने का एक अन्य विकल्प बाश में एएनएसआई-सी उद्धृत सुविधा का उपयोग करना है , जैसा कि अन्य उत्तरों में से एक में उल्लेख किया गया है
TheDudeAbides


1

मेरे पास एक समान कार्य था, और काम करने के लिए उपरोक्त पर्ल समाधान प्राप्त करने में सक्षम नहीं था।

यहाँ मेरा समाधान है:

perl -i -pe "BEGIN{undef $/;} s/^\[mysqld\]$/[mysqld]\n\ncollation-server = utf8_unicode_ci\n/sgm" /etc/mysql/my.cnf

स्पष्टीकरण:

मेरे /etc/mysql/my.cnf फ़ाइल में एक लाइन की खोज करने के लिए एक नियमित अभिव्यक्ति का उपयोग करता है जिसमें केवल शामिल है [mysqld]और इसके साथ प्रतिस्थापित किया गया है

[mysqld] collation-server = utf8_unicode_ci

प्रभावी रूप collation-server = utf8_unicode_ciसे लाइन वाले लाइन के बाद लाइन जोड़ना [mysqld]


0

मुझे हाल ही में मैक और लिनक्स ओएस दोनों के लिए ऐसा करना पड़ा और कई पोस्ट के माध्यम से ब्राउज़ करने और कई चीजों की कोशिश करने के बाद, मेरी विशेष राय में मुझे कभी भी वह नहीं मिला जहां मैं चाहता था: एक सरल पर्याप्त रूप से ज्ञात समाधान का उपयोग करके समझने के लिए पर्याप्त है और सरल पैटर्न, एक लाइनर, पोर्टेबल के साथ मानक आदेश, अधिक बाधाओं में जोड़ने के लिए विस्तार योग्य। फिर मैंने इसे एक अलग नजरिए से देखने की कोशिश की, जब मैंने महसूस किया कि मैं "वन-लाइनर" विकल्प के बिना कर सकता हूं अगर "2-लाइनर" मेरे बाकी मानदंडों को पूरा करता है। अंत में मैं इस समाधान के साथ आया था जो मुझे उबंटू और मैक दोनों में काम करता है जो मैं सभी के साथ साझा करना चाहता था:

insertLine=$(( $(grep -n "foo" sample.txt | cut -f1 -d: | head -1) + 1 ))
sed -i -e "$insertLine"' i\'$'\n''bar'$'\n' sample.txt

पहले कमांड में, grep "foo" युक्त लाइन नंबरों की तलाश करता है, कट / हेड 1 घटना का चयन करता है, और अंकगणितीय सेशन में वृद्धि होती है जो पहली घटना लाइन नंबर 1 से होती है क्योंकि मैं घटना के बाद सम्मिलित करना चाहता हूं। दूसरे कमांड में, यह एक इन-प्लेस फ़ाइल एडिट है, "i" डालने के लिए: एक एएनआई-सी जो नई लाइन, "बार", फिर एक और नई लाइन। परिणाम "फू" लाइन के बाद "बार" युक्त एक नई लाइन जोड़ रहा है। इन 2 आदेशों में से प्रत्येक को अधिक जटिल संचालन और मिलान के लिए विस्तारित किया जा सकता है।

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