প্যাটার্নের (মার্কার) আগে কোনও ফাইলের বিষয়বস্তু অন্য কোনও ফাইলে কীভাবে ?োকানো যায়?


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লাইন যে "পয়েন্টার" রয়েছে আগে।




আমি ইতিমধ্যে এই কারণে বন্ধ করার জন্য এসও প্রশ্নকে ভোট দিয়েছি, এই প্রশ্নটি বন্ধ করার আর কোনও কারণ নেই। বিটিডব্লিউ, প্রশ্নটি এসও এর চেয়েও খারাপ মানের, সুতরাং যুক্তিটি এটি বন্ধ করার নির্দেশ দেয় এবং এটি নয়।
পিটার বলেছেন মনিকা

উত্তর:


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

এটি কাজ করছে, তবে এটি পয়েন্টারযুক্ত লাইনটি সরিয়ে
ফেলছে

একইভাবে, কীভাবে "পয়েন্টার" এর পরে
ইউজার 1228191

@ user1228191 প্রথমটি স্থির করে, দ্বিতীয়টি যুক্ত করে।
কেভিন

'পার্ল' সংস্করণটি কাজ করছে বলে মনে হচ্ছে না। কনসোল system("cat innerfile")আউটপুট innerfile। আমি কিছু অনুপস্থিত করছি?
কর্টিক

awk কমান্ড [gawk '/ <body> / {থাকাকালীন (getline লাইন <"OME হোম / বিন / শ্রেনসেনারিও.স্টাইল") {মুদ্রণ লাইন}} //' 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। আপনি যদি প্রতিটি মিলের লাইনের আগে এটি gsertোকাতে চান তবে লোকাল পতাকা যুক্ত করুন:

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

এই ডাব্লু / সম্পর্কে জানার কয়েকটি উপায় রয়েছে 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 -

সমস্ত sedএস -স্ট্যান্ডার্ড ইনপুট বোঝার জন্য ব্যাখ্যা করবেন না , তবে অনেকেই করেন। ( পসআইএক্স বলছে স্ট্যান্ডার্ড-ইন মানে sedসমর্থন -করা উচিত যদি প্রয়োগকারীরা -স্ট্যান্ডার্ড-ইন বলতে চান তবে ???)

আরেকটি উপায় হ'ল সংযুক্ত কন্টেন্টটি পরিচালনা করা। এখানে আরও একটি কমান্ড রয়েছে যা একইভাবে আউটপুটকে শিডিয়ুলr করে ইডটি করে, এবং sedএটি প্রয়োগ করে এবং rসেগুলি যাতে স্ক্রিপ্ট করা হয় সেভাবে তা সংযোজন করবে । এটা ব্যবহার করে entails - এটি একটি সামান্য আরো জড়িত যদিও এর sedথেকে append Pointerঅন্য আউটপুট ম্যাচ sedতার লিপিতে।

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যে ইনপুট লাইন দ্রণ !কিন্তু /&/এক আমরা শুধু প্যাটার্ন-safed; এবং তারপরে dসমস্ত একাদশ করতে হবে। pদ্বিতীয়টি কমান্ডগুলি মুদ্রণ করুন sed, এবং তারপর আমাদের সংরক্ষিত অনুলিপিটিতে কাজ xকরতে hপুরানো এবং প্যাটার্নের বাফারগুলি পরিবর্তন করুন ।
  3. s|.|r file1&a\\&|p;q
    • আমরা এখানে কেবলমাত্র \nচরটিই কাজ করি একটি ইলাইন, কারণ sedআমরা যখন Hলাইনটি আগে প্রবীণ করি তখন একটিটিকে চাপ দেওয়া হবে । সুতরাং আমরা কমান্ডটি সন্নিবেশ করলাম r file1এবং এটি আমাদের \newline এর সাথে অনুসরণ করব তারপরে ppend এর a\\জন্য কমান্ডটি aএকটি \newline অনুসরণ করবে। আমাদের শীর্ষস্থানীয় বাকী সমস্ত রেখাগুলি Hসেই শেষ \newline অনুসরণ করে ।

প্রথম যে স্ক্রিপ্টটি লিখেছেন তা দেখতে এরকম কিছু দেখাচ্ছে:

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

মূলত দ্বিতীয়টি sedপ্রতিটি লাইন মুদ্রণ করবে তবে প্রথমটি sedসেটাকে aপেপেন্ড করার জন্য সেট করে । সেই নির্দিষ্ট লাইনের জন্য স্ট্যান্ডার্ড-আউটতে দুটি বিলম্বিত লেখাগুলি নির্ধারিত হয় - প্রথমটি হ'ল rইড file1এবং দ্বিতীয়টি এটির পরে আমরা যে লাইনের চাই তার একটি অনুলিপি। এই ক্ষেত্রে প্রথম sedচিকিত্সা করা এমনকি প্রয়োজনীয় নয় (দেখুন? কোনও ব্যাকস্ল্যাশ নেই) তবে যখনই কোনও প্যাটার্ন ম্যাচটি ইনপুট হিসাবে পুনরায় প্রকাশ করা হয় আমি নিরাপদে যেভাবে এখানে থাকি তা নিরাপদে পালানো গুরুত্বপূর্ণ।

যাইহোক, তাই ... কয়েকটি উপায় আছে।


2

এটি এডাব্লুকে দিয়ে মোটামুটি সহজ:

প্যাটার্ন = "পয়েন্টার" এর আগে ফাইল 2 এ ফাইল 1

প্রথমে ফাইল 1 এর সামগ্রীগুলি একটি ভেরিয়েবলের মধ্যে লোড করুন

f1="$(<File1)"

তারপর সন্নিবেশ করুন

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

(বা, যদি আপনি "পয়েন্টার" এর পরে ফাইল 1 সন্নিবেশ করতে চান)

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

2

আমার পছন্দের উপায়: উদ্বেগজনক

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

এর ফলে প্রতিটি প্রতিস্থাপন করবে CHANGEME মধ্যে occurence origfile বিষয়বস্তুর সঙ্গে file2insertচেঞ্জেমের প্রথম উপস্থিতিটি প্রতিস্থাপন করতে শেড থেকে শেষ জি সরান ।


আপনি $xআপনার প্রথম কমান্ডটিতে কীভাবে ব্যবহার করতে পারেন , যখন এটি কেবলমাত্র দ্বিতীয় কমান্ডে সংজ্ঞায়িত হয়?
টোটার

প্রথম কমান্ডের "$ x" হ'ল দ্বিতীয় কমান্ডের এনভ্যাসউবস্ট দ্বারা মূল্যায়নের জন্য কেবল স্থানধারক। সেড স্ক্রিপ্টের একক উদ্ধৃতি সহ, shell x আপনার শেল দ্বারা মূল্যায়ন হয় না।
এনআরসি

2

[প্যাটার্নের আগে অন্য ফাইলে ফাইলের সামগ্রী sertোকান]

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

[প্যাটার্ন পরে]

sed -i '/PATTERN/r file1' file2

Nসুন্দরভাবে কাজ করে, তবে নয় যদি PATTERN ইনপুটটির শেষ লাইনের সাথে মেলে
সুদীপ

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.