पैटर्न (मार्कर) से पहले किसी अन्य फ़ाइल में फ़ाइल की सामग्री कैसे डालें?


32

File1 सामग्री:

line1-file1      "1" 
line2-file1      "2"
line3-file1      "3" 
line4-file1      "4" 

File2 सामग्री:

line1-file2     "25"  
line2-file2     "24"  
Pointer-file2   "23"  
line4-file2     "22" 
line5-file2     "21"

पर्ल / शेल स्क्रिप्ट के निष्पादन के बाद, File2सामग्री बननी चाहिए:

line1-file2     "25"  
line2-file2     "24" 
line1-file1      "1" 
line2-file1      "2"
line3-file1      "3" 
line4-file1      "4" 
Pointer-file2   "23" 
line4-file2     "22" 
line5-file2     "21"

यानी की सामग्री को पेस्ट File1में File2लाइन है कि "सूचक" शामिल करने से पहले।


1
इसके अलावा में पूछा StackOverflow
ग्लेन जैकमैन

इसके अलावा stackoverflow.com/questions/11243102/…
Necreaux

मैंने इस कारण से पहले से ही एसओ प्रश्न को बंद करने के लिए मतदान किया, इस प्रश्न को बंद करने का कोई और कारण नहीं है। Btw, सवाल एसओ पर बहुत खराब गुणवत्ता है, इसलिए तर्क इसे बंद करने का आदेश देता है और यह नहीं।
पीटर ने कहा कि मोनिका

जवाबों:


33

sed उसके लिए एक फ़ंक्शन है, और संशोधन इनलाइन कर सकते हैं:

sed -i -e '/Pointer/r file1' file2

लेकिन यह फ़ाइल 1 के ऊपर आपकी पॉइंटर लाइन डालता है । इसे नीचे रखने के लिए, विलंब लाइन आउटपुट:

sed -n -i -e '/Pointer/r file1' -e 1x -e '2,${x;p}' -e '${x;p}' file2 

8
क्या आप बता सकते हैं कि क्या -e 1x -e '2,${x;p}' -e '${x;p}'करते हैं? मैं समझता हूं कि आप पैटर्न बफर में सामान का आदान-प्रदान करते हैं और फिर इसे प्रिंट करते हैं लेकिन मुझे नहीं पता कि आपने -nशुरुआत में शांत विकल्प क्या और क्यों जोड़ा ।
एचडीएल

@ jfg956 क्या मूल फ़ाइल से 'पॉइंटर' भाग को केवल स्थानापन्न और हटाना संभव है। यह मैं सेड के दूसरे स्वीप से समझ सकता हूं, लेकिन क्या एक रन में ऐसा करना संभव है?
अलेक्जेंडर सीस्का

17

बिना उपयोग sedया awk...

सबसे पहले, अपनी रेखा को खोजें, जिस पर आपका पैटर्न है:

line=$(grep -n 'Pointer' file2 | cut -d ":" -f 1)

फिर, वांछित परिणाम के उत्पादन के लिए 3 कमांड का उपयोग करें:

{ head -n $(($line-1)) file2; cat file1; tail -n +$line file2; } > new_file

इसमें फ़ाइल को 3 बार एक्सेस करने का दोष है file2, लेकिन समाधान sedकी तुलना में अधिक स्पष्ट हो सकता है awk


10

awkयह काफी आसान बनाता है।
फ़ाइल से पहले लाइन डालें:

awk '/Pointer/{while(getline line<"innerfile"){print line}} //' outerfile >tmp
mv tmp outerfile

Pointerलाइन के बाद आंतरिक फ़ाइल प्रिंट बनाने के लिए , बस पैटर्न के क्रम को स्विच करें (आपको डिफ़ॉल्ट कार्रवाई करने के लिए अर्धविराम जोड़ने की आवश्यकता है), और आप lineचर को छोड़ सकते हैं :

awk '//; /Pointer/{while(getline<"innerfile"){print}}' outerfile >tmp
mv tmp outerfile

और सिर्फ इसलिए कि किसी ने perlअभी तक उपयोग नहीं किया है,

# insert file before line
perl -e 'while(<>){if($_=~/Pointer/){system("cat innerfile")};print}' outerfile

# after line
perl -e 'while(<>){print;if($_=~/Pointer/){system("cat innerfile")}}' outerfile

इसका काम, लेकिन इसके पॉइंटर को हटाने वाली लाइन है
user1228191

इसी तरह, फ़ाइल 2 में फ़ाइल 1 की सामग्री को कैसे चिपकाएँ, उसके बाद "पॉइंटर" युक्त लाइन का उपयोग करके awk
user1228191

@ user1228191 ने पहला, दूसरा जोड़ा।
केविन

'पर्ल' संस्करण काम नहीं कर रहा है। कंसोल system("cat innerfile")के innerfileलिए आउटपुट । क्या मैं कुछ भूल रहा हूँ?
kaartic

awk कमांड [gawk '/ <body> / {(जबकि लाइन लाइन <"$ गृह / बिन / SrunScenario.style") {प्रिंट लाइन}} // // index.html> new_index.html] बस लूप और लाखों लाइनें प्रिंट करता है । gawk V4.2.0 मुझे यहां क्या याद आ रहा है?
JESii

7

इसके लिए एक आसान काम ed:

ed -s file1 <<IN
/Pointer/-r file2
,p
q
IN

-r file1निर्दिष्ट लाइन के बाद निर्दिष्ट फ़ाइल में पढ़ता है, जो इस मामले में पहली पंक्ति के मिलान से पहले की रेखा है Pointer। तो यह file2केवल एक बार की सामग्री को सम्मिलित करेगा भले ही Pointerकई लाइनों पर हो। यदि आप प्रत्येक मिलान पंक्ति को gलोबाल ध्वज जोड़ने से पहले सम्मिलित करना चाहते हैं :

ed -s file1 <<IN
g/Pointer/-r file2
,p
q
IN

बदलें ,pके साथ wआप इन-जगह फाइल को संपादित करना चाहते हैं।


स्वीकृत sedउत्तर अधिकांश मामलों के लिए काम करता है लेकिन यदि मार्कर अंतिम पंक्ति में है, तो कमांड अपेक्षित रूप से काम नहीं करेगा: यह File1मार्कर के बाद की सामग्री को सम्मिलित करेगा ।
मैंने शुरू में इसके साथ प्रयास किया है:

sed '/Pointer/{r file1
N}' file2

जो ठीक भी काम करता है (जैसा rकि चक्र के अंत में अपना जादू करेगा) लेकिन एक ही समस्या है कि मार्कर अंतिम पंक्ति पर है (अंतिम Nपंक्ति के बाद कोई एक्सट्रीम लाइन नहीं है )। उस पर काम करने के लिए, आप अपने इनपुट में एक नई पंक्ति जोड़ सकते हैं:

sed '/Pointer/{              # like the first one, but this time even if the
r file1                      # marker is on the last line in File2 it
N                            # will be on the second to last line in
}                            # the combined input so N will always work;
${                           # on the last line of input: if the line is
/^$/!{                       # not empty, it means the marker was on the last
s/\n$//                      # line in File2 so the final empty line in the
}                            # input was pulled i\n: remove the latter;
//d                          # if the line is empty, delete it
}' file2 <(printf %s\\n)

यह file2प्रत्येक मिलान रेखा से पहले सामग्री सम्मिलित करेगा । पहली मिलान रेखा से पहले इसे डालने के लिए आप एक lऊप का उपयोग कर सकते हैं और nफ़ाइल के अंत तक प्राप्त होने तक केवल बाहरी पंक्ति में खींच सकते हैं:

sed '/Pointer/{
r file2
N
:l
$!n
$!bl
}
${
/^$/!{
s/\n$//
}
//d
}' file1 <(printf %s\\n)

इन sedसमाधानों के साथ आप इन -प्लेस को संपादित करने की क्षमता खो देते हैं (लेकिन आप किसी अन्य फ़ाइल में रीडायरेक्ट कर सकते हैं)।


6

फ़ाइल 2 में लाइनों को पढ़ने के लिए एक लूप का उपयोग करें। यदि आपको एक लाइन शुरू होती है Pointer, तो फ़ाइल 1 का प्रिंट आउट लें। यह नीचे दिखाया गया है:

#!/bin/bash
while IFS= read -r line
do
    if [[ "$line" =~ ^Pointer.*$ ]]
    then
        cat file1
    fi
    echo "$line"
done < file2

4

इस w / के बारे में जाने के कुछ तरीके हैं sed। स्वीकृत उत्तर में अनुशंसित एक तरीका विलंब से पढ़ा गया है। यह भी लिखा जा सकता है:

sed -e '$!N;P;/\nPointer/r file1' -e D file2

... होल्ड बफर के साथ कहीं और लागू किए गए लुक-पीछे के बजाय थोड़ा स्पष्ट लुक-फॉरवर्ड। यह अनिवार्य रूप से अंतिम लाइन के साथ एक ही समस्या होगी कि @don_crissti नोट, हालांकि, क्योंकि लाइन चक्र N को बढ़ाता है और read कमांड लाइन नंबर द्वारा लागू किया जाता है।

आप इसे प्राप्त कर सकते हैं:

echo | sed -e '$d;N;P;/\nPointer/r file1' -e D file2 -

सभी seds -मतलब मानक इनपुट की व्याख्या नहीं करेंगे , लेकिन कई करते हैं। ( POSIX का कहना है कि मानक का मतलब करने के लिए sedसमर्थन करना चाहिए -- यदि कार्यान्वयनकर्ता -मानक का मतलब चाहता है ????

दूसरा तरीका यह है कि क्रम में संलग्न सामग्री को संभालना है। एक और कमांड है जो आउटपुट को उसी तरह से शेड्यूलr करता है जैसे ead करता है, और वे sedइसे लागू करेंगे और rजिस क्रम में वे स्क्रिप्टेड हैं , उसी में रीड करेंगे । हालांकि यह थोड़ा अधिक शामिल है - यह अपनी स्क्रिप्ट में दूसरे के आउटपुट के लिए मैच को ppend sedकरने के लिए एक का उपयोग करने पर जोर देता है ।aPointersed

sed '   /Pointer/!d                  #only operate on first match
        s/[]^$&\./*[]/\\&/g;H        #escape all metachars, Hold
        s|.*|/&/!p;//!d|p;g          #print commands, exchange
        s|.|r file1&a\\&|;q' file2|  #more commands, quit
        sed -nf - file2              #same input file

इसलिए मूल रूप से पहला sedदूसरा sedस्क्रिप्ट लिखता है , जो दूसरा sedमानक-इनपुट (शायद ...) पर पढ़ता है और बदले में लागू होता है। पहले sedकेवल पहले मैच के लिए काम करता Pointerहै, और उसके बाद qइनपुट का उपयोग करता है। इसका काम है ...

  1. s/[]^$&\./*[]/\\&/g;H
    • सुनिश्चित करें कि सभी पैटर्न चार्ट सुरक्षित रूप से बैकस्लैश-बच गए हैं क्योंकि दूसरे sedको हर बिट की व्याख्या करने की आवश्यकता है जो इसे सही ढंग से प्राप्त करने के लिए सचमुच पढ़ता है। एक बार हो जाने के बाद, Hपुरानी जगह पर एक कॉपी रख दें ।
  2. s|.*|/&/!p;//!d|p; x
    • हर इनपुट लाइन sedको pरिंट करने के लिए दूसरे को बताएं, !लेकिन /&/हम सिर्फ पैटर्न-सेफेड हैं; और फिर dसभी समान करने के लिए। pदूसरे नंबर पर कमांड को रिंट करें sed, फिर हमारी सेव की हुई कॉपी पर काम करने के xलिए hपुराने और पैटर्न बफ़र्स को बदलें ।
  3. s|.|r file1&a\\&|p;q
    • हमारे यहां काम करने वाला \nएकमात्र चार्ट एक ईवलाइन है, क्योंकि sedजब हम Hलाइन को पहले से बड़ा करते हैं, तो एक पूर्वनिर्मित होगा । तो हम आदेश डालने r file1और हमारे साथ इसे का पालन \newline तो आदेश a\\के लिए append एक से भी पीछा किया \newline। हमारी बड़ी Hलाइन के बाकी सभी अंतिम \nईवलाइन का अनुसरण करते हैं ।

पहले लिखी जाने वाली स्क्रिप्ट कुछ इस तरह दिखती है:

/Pointer-file2   "23"/!p;//!d
r file1
a\
Pointer-file2   "23"

मूल रूप से दूसरा sedहर लाइन को प्रिंट करेगा लेकिन पहला sedइसे append पर सेट करता है । उस विशेष पंक्ति के लिए दो विलम्ब से लिखी गई मानक-आउट निर्धारित हैं - पहली read है file1और दूसरी उस पंक्ति की एक प्रति है जिसे हम उसके बाद चाहते हैं। sedइस मामले में पहला डॉक्टरेट करना भी आवश्यक नहीं है (देखें? कोई बैकस्लैश) नहीं, लेकिन जब भी कोई पैटर्न मैच इनपुट के रूप में पुन: प्रस्तुत किया जाता है, तो मैं यहां से सुरक्षित रूप से बचना महत्वपूर्ण है।

वैसे भी, इसलिए ... कुछ तरीके हैं।


2

यह AWK के साथ काफी सरल है:

File1 में File2 पैटर्न से पहले = "पॉइंटर"

पहले फ़ाइल 1 की सामग्री को एक चर में लोड करें

f1="$(<File1)"

फिर प्रविष्टि करें

awk -vf1="$f1" '/Pointer/{print f1;print;next}1' file2

(या, यदि आप "सूचक" के बाद File1 सम्मिलित करना चाहते हैं)

awk -vf1="$f1" '/Pointer/{print;print f1;next}1' file2

2

मेरा पसंदीदा तरीका: टेम्प्लेटिंग

sed 's/CHANGEME/$x/g' origfile | x="$(<file2insert)" envsubst '$x' > newfile

यह हर जगह लेगा CHANGEME में घटना origfile की सामग्री के साथ file2insertCHANGEME की केवल पहली घटना को बदलने के लिए sed से अंतिम g निकालें ।


$xजब आप केवल अपनी दूसरी कमांड में परिभाषित करते हैं, तो आप अपनी पहली कमांड में कैसे उपयोग कर सकते हैं ?
टॉटर

पहले कमांड में "$ x" केवल एक प्लेसहोल्डर है जिसका मूल्यांकन दूसरे कमांड में एनवसबस्ट द्वारा किया जाता है। सीड स्क्रिप्ट के एकल उद्धरणों के साथ, $ x का आपके शेल द्वारा मूल्यांकन नहीं किया जाता है।
एनआरसी

2

[फ़ाइल सामग्री को किसी अन्य फ़ाइल से पहले सम्मिलित करें]

sed -i '/PATTERN/r file1' -e //N file2

[पैटर्न के बाद]

sed -i '/PATTERN/r file1' file2

Nअच्छी तरह से काम करता है, लेकिन अगर PATTERN इनपुट की अंतिम पंक्ति से मेल नहीं खाता है
Sundeep

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