NON GNU awk সহ জায়গায় পরিবর্তনগুলি সংরক্ষণ করুন


9

আমি একটি প্রশ্ন এসেছি (নিজেই নিজেই) যেখানে ওপিকে ইনপুট_ফাইলে নিজে সম্পাদনা করতে হবে এবং অপারেশনটি সংরক্ষণ করতে হবে।

আমি একক ইনপুট_ফাইলে জানি যে আমরা নিম্নলিখিতটি করতে পারি:

awk '{print "test here..new line for saving.."}' Input_file > temp && mv temp Input_file

এখন আসুন আমরা আমাদের ফাইলের একই ধরণের বিন্যাসে পরিবর্তন করতে হবে বলে মনে করি (এখানে .txt অনুমান করুন)।

আমি এই সমস্যার জন্য যা চেষ্টা করেছি / ভেবেছি: এর পদ্ধতির .txt ফাইল লুপের জন্য যাচ্ছি এবং একক কলawkকরা একটি বেদনাদায়ক এবং প্রস্তাবিত প্রক্রিয়া নয়, কারণ এটি অপ্রয়োজনীয় সিপিইউ চক্রকে অপচয় করবে এবং আরও সংখ্যক ফাইলের জন্য এটি আরও বেশি হবে মন্থর।

সুতরাং কোনও নন জিএনইউ awkদিয়ে ইনপ্লেস বিকল্প সমর্থন করে না এমন একাধিক ফাইলের জন্য ইনপ্লেস সম্পাদনা সম্পাদনের জন্য এখানে সম্ভবত কী করা যায় । আমি এই থ্রেড দিয়েও জাজের জায়গায় জায়গায় পরিবর্তনগুলি সংরক্ষণ করে চলেছি তবে কোন জিএনইউ অ্যাডাব্লু ভাইস এবং awkনিজের মধ্যে একাধিক ফাইল পরিবর্তন করার পক্ষে তেমন কিছুই নেই , যেহেতু একটি নন জিএনইউ অ্যাডকের inplaceপক্ষে বিকল্প নেই।

দ্রষ্টব্য: আমিbashযেহেতু ট্যাগযুক্ত করছি, আমার উত্তরের অংশে আমি অস্থায়ী ফাইলগুলির প্রকৃত ইনপুট_ফাইলে নামগুলিতে নাম যুক্ত করতে ব্যাশ কমান্ড ব্যবহার করেছি যাতে এটি যুক্ত করা হয়।



সম্পাদনা: এড স্যারের মন্তব্য অনুসারে এখানে নমুনাগুলির উদাহরণ যুক্ত করা হয়েছে, যদিও এই থ্রেডের কোডটির উদ্দেশ্যটি সাধারণ উদ্দেশ্য ইনপ্লেস সম্পাদনা দ্বারাও ব্যবহার করা যেতে পারে।

নমুনা ইনপুট_ফাইল (গুলি):

cat test1.txt
onetwo three
tets testtest

cat test2.txt
onetwo three
tets testtest

cat test3.txt
onetwo three
tets testtest

প্রত্যাশিত আউটপুট নমুনা:

cat test1.txt
1
2

cat test2.txt
1
2

cat test3.txt
1
2

1
আকর্ষণীয় এবং প্রাসঙ্গিক অবাক সমস্যা ++
অনুভা

1
@ রবীন্দ্রসিংহ ১৩ যদি আপনার কাছে এটি প্রয়োগ করার জন্য পুরো গোছা ফাইল থাকে, তবে কেন একটি সিঙ্গল কল awk(সম্ভবত একটি সাবসিলে) বা একটি {...}বদ্ধ গ্রুপ ব্যবহার করবেন না এবং তারপরে ফলাফলটি আকাঙ্ক্ষিত আউটপুট ফাইলটিতে লিখুন (প্রতিটি ইনপুট ফাইলের জন্য, বা সমস্ত ইনপুট ফাইলের জন্য একটি সম্মিলিত ফাইল)। তারপরে আপনি কেবল সাবস্কেল বা ব্রেস-সংযুক্ত গ্রুপের আউটপুটটি বর্তমান ফাইলটিতে লিখিত হচ্ছেন? awkকমান্ডটি অনুসরণ করে কেবল ইনপুট ফাইলগুলির একটি স্ট্রিং অন্তর্ভুক্ত করে ক্রমান্বয়ে সমস্ত ফাইল (বা অনুরূপ কিছু) প্রসেস করা হবে ??
ডেভিড সি র্যাঙ্কিন

@ ডেভিডসি.র্যাঙ্কিন, এর জবাব দেওয়ার জন্য আপনাকে ধন্যবাদ। হ্যাঁ, আপনি স্যার বলছেন এমন একই ধরণের স্টাফ পোস্ট করেছি, আমার উত্তরটিও এই প্রশ্নটিতে পোস্ট করা হয়েছে লেমমে একই স্যার, চিয়ার্স সম্পর্কে আপনার মতামত জানুন।
রবীন্দ্রসিংহ 13

1
কিছুক্ষণ ঘুমানোর পরে এবং এটি সম্পর্কে চিন্তাভাবনা করার পরে, আমি awk {..} file1 .. fileXপরিবর্তিত ফাইলটি লিখতে 2 টি বিকল্প (1) দেখতে পাচ্ছি , যেমন temp01এবং পরবর্তী ফাইলটি প্রক্রিয়া করার সময় আপনার পরবর্তী পুনরাবৃত্তিতে, mv -f tmp01 input01পরিবর্তিত ডেটা দিয়ে ইনপুট ফাইলকে ওভাররাইট করতে একটি ব্যবহার করুন; বা (2) কেবল একটি নতুন ডিরেক্টরির লিখতে ./tmp/tmp01 ... ./tmp/tmp0Xচালানোর সময় awkফাইল উপর একটি লুপ সঙ্গে স্ক্রিপ্ট এবং ফলো-আপ ./tmpডিরেক্টরি ও যেমন mv -f "$i" "input_${i##*[^0-9]}"(অথবা যাই হোক না কেন সম্প্রসারণ আপনি পুরানো ইনপুট ফাইল প্রতিস্থাপন করা প্রয়োজন।
ডেভিড সি র্যাঙ্কিন

@ ডেভিডসি। র্যাঙ্কিন, আপনার মতামতগুলি এখানে স্যারকে জানাতে দেওয়ার জন্য আপনাকে ধন্যবাদ, আইএমএইচও ১ ম বিকল্পটি কিছুটা ঝুঁকিপূর্ণ হতে পারে, যেহেতু আমরা awkসম্পূর্ণ কোড সম্পন্ন না করেই কিছু করছি , ২ য় বিকল্পটি আমার পরামর্শ অনুসারে যা ব্যবহার করছি তা হ'ল আপনি যদি সলিউশন সলিউশন সম্পর্কে আপনার চিন্তাভাবনা জানাতে পারতেন তবে কৃতজ্ঞ হবেন।
রবীন্দ্রসিংহ 13

উত্তর:


6

যেহেতু এই থ্রেডের মূল লক্ষ্যটি হ'ল নন জিএনইউতে কীভাবে সংরক্ষণ করা যায় awkতাই আমি প্রথমে এর টেম্পলেটটি পোস্ট করছি যা যে কোনও প্রয়োজনে যে কোনও ব্যক্তিকে সহায়তা করবে তাই তাদের মূল ব্লকটি রেখে তাদের কোডে সংযোজন / সংযোজন BEGINএবং ENDবিভাগের প্রয়োজন প্রয়োজনীয়তা এবং এরপরে এটি ইনপ্লেস সম্পাদনা করা উচিত:

দ্রষ্টব্য: নিম্নলিখিতটি তার সমস্ত আউটপুট আউটপুট_ফাইলে লিখবে, সুতরাং আপনি যদি স্ট্যান্ডার্ড আউটপুটে কোনও কিছু মুদ্রণ করতে চান তবে দয়া করেনিম্নলিখিতটিprint...ছাড়াইকেবলবিবৃতিযুক্ত করুন> (out)

জেনেরিক টেম্পলেট:

awk -v out_file="out" '
FNR==1{
close(out)
out=out_file count++
rename=(rename?rename ORS:"") "mv \047" out "\047 \047" FILENAME "\047"
}
{
    .....your main block code.....
}
END{
 if(rename){
   system(rename)
 }
}
' *.txt


নির্দিষ্ট প্রদত্ত নমুনার সমাধান:

আমি awkনিজের মধ্যে নিম্নলিখিত পদ্ধতির সাথে হাজির হয়েছি (যুক্ত হওয়া নমুনাগুলির জন্য এটি সমাধান করার এবং ইনপুট_ফাইলে নিজেই আউটপুট সংরক্ষণ করার জন্য আমার পদ্ধতিটি)

awk -v out_file="out" '
FNR==1{
  close(out)
  out=out_file count++
  rename=(rename?rename ORS:"") "mv \047" out "\047 \047" FILENAME "\047"
}
{
  print FNR > (out)
}
END{
  if(rename){
    system(rename)
  }
}
' *.txt

দ্রষ্টব্য: এটি সম্পাদিত আউটপুটটি কেবল ইনপুট_ফাইলে (গুলি) সংরক্ষণ করার জন্য একটি পরীক্ষা, যে কেউ তার প্রোগ্রামের তার শেষ অংশের সাথে এর বিগিন বিভাগটি ব্যবহার করতে পারে, মূল অংশটি নির্দিষ্ট প্রশ্নের প্রয়োজন অনুযায়ীই হওয়া উচিত।

যথাযথ সতর্কতা: এছাড়াও যেহেতু এই পদ্ধতির ফলে পথে একটি নতুন অস্থায়ী আউট ফাইল তৈরি করা হয়েছে তা নিশ্চিত হয়ে নিন যে আমাদের সিস্টেমে পর্যাপ্ত জায়গা রয়েছে, যদিও চূড়ান্ত পরিণতিতে এটি কেবলমাত্র প্রধান ইনপুট_ফাইলে রাখবে তবে অপারেশন চলাকালীন এটি সিস্টেম / ডিরেক্টরিতে স্থান প্রয়োজন needs



নিম্নোক্ত উপরের কোডের জন্য একটি পরীক্ষা রয়েছে।

একটি উদাহরণ সহ প্রোগ্রামের সম্পাদন: ধরে নেওয়া যাক নিম্নলিখিতগুলি.txtইনপুট_ফাইলে রয়েছে:

cat << EOF > test1.txt
onetwo three
tets testtest
EOF

cat << EOF > test2.txt
onetwo three
tets testtest
EOF

cat << EOF > test3.txt
onetwo three
tets testtest
EOF

এখন যখন আমরা নিম্নলিখিত কোডগুলি চালাই:

awk -v out_file="out" '
FNR==1{
  close(out)
  out=out_file count++
  rename=(rename?rename ORS:"") "mv \047" out "\047 \047" FILENAME "\047"
}
{
  print "new_lines_here...." > (out)
}
END{
  if(rename){
    system("ls -lhtr;" rename)
  }
}
' *.txt

দ্রষ্টব্য: এটি কোন আউটপুট ফাইলগুলি তৈরি করছে (অস্থায়ী ভিত্তিতে) তা দেখার জন্যআমার কাছেবিভাগেস্থানls -lhtrরয়েছেsystemকারণ পরবর্তীতে এটি তাদের প্রকৃত নামে পুনরায় নামকরণ করবে।

-rw-r--r-- 1 runner runner  27 Dec  9 05:33 test2.txt
-rw-r--r-- 1 runner runner  27 Dec  9 05:33 test1.txt
-rw-r--r-- 1 runner runner  27 Dec  9 05:33 test3.txt
-rw-r--r-- 1 runner runner  38 Dec  9 05:33 out2
-rw-r--r-- 1 runner runner  38 Dec  9 05:33 out1
-rw-r--r-- 1 runner runner  38 Dec  9 05:33 out0

আমরা যখন স্ক্রিপ্টটি চালানোর ls -lhtrপরে awkশেষ করি তখন আমরা কেবল .txtসেখানে ফাইল দেখতে পেতাম ।

-rw-r--r-- 1 runner runner  27 Dec  9 05:33 test2.txt
-rw-r--r-- 1 runner runner  27 Dec  9 05:33 test1.txt
-rw-r--r-- 1 runner runner  27 Dec  9 05:33 test3.txt


ব্যাখ্যা: উপরের কমান্ডের বিশদ ব্যাখ্যা এখানে যুক্ত করা হচ্ছে:

awk -v out_file="out" '                                    ##Starting awk program from here, creating a variable named out_file whose value SHOULD BE a name of files which are NOT present in our current directory. Basically by this name temporary files will be created which will be later renamed to actual files.
FNR==1{                                                    ##Checking condition if this is very first line of current Input_file then do following.
  close(out)                                               ##Using close function of awk here, because we are putting output to temp files and then renaming them so making sure that we shouldn't get too many files opened error by CLOSING it.
  out=out_file count++                                     ##Creating out variable here, whose value is value of variable out_file(defined in awk -v section) then variable count whose value will be keep increment with 1 whenever cursor comes here.
  rename=(rename?rename ORS:"") "mv \047" out "\047 \047" FILENAME "\047"     ##Creating a variable named rename, whose work is to execute commands(rename ones) once we are done with processing all the Input_file(s), this will be executed in END section.
}                                                          ##Closing BLOCK for FNR==1  condition here.
{                                                          ##Starting main BLOCK from here.
  print "new_lines_here...." > (out)                       ##Doing printing in this example to out file.
}                                                          ##Closing main BLOCK here.
END{                                                       ##Starting END block for this specific program here.
  if(rename){                                              ##Checking condition if rename variable is NOT NULL then do following.
    system(rename)                                         ##Using system command and placing renme variable inside which will actually execute mv commands to rename files from out01 etc to Input_file etc.
  }
}                                                          ##Closing END block of this program here.
' *.txt                                                    ##Mentioning Input_file(s) with their extensions here.

1
মজাদার ঘটনা: আপনি যদি FNR==1ব্লকে ইনপুট ফাইলটি মুছে ফেলেন তবে আপনি স্থানে থাকা পরিবর্তনগুলি সংরক্ষণ করতে পারেন। ভালো লেগেছে awk 'FNR==1{system("rm " FILENAME)} {print "new lines" > FILENAME}' files...। এটি মোটেই নির্ভরযোগ্য নয় (সম্পূর্ণ ডেটা হ্রাস হওয়ার সম্ভাবনা রয়েছে) তবে তবুও এটি বেশিরভাগ ক্ষেত্রে সূক্ষ্মভাবে কাজ করে: ডি
ওগুজ ইসমাইল

1
কাজের চারপাশে খুব সুস্পষ্টভাবে ব্যাখ্যা করা হয়েছে
অনুভভা

3

আমি যদি এই কাজটি করার চেষ্টা করি তবে আমি সম্ভবত এই জাতীয় কিছু নিয়ে যাব:

$ cat ../tst.awk
FNR==1 { saveChanges() }
{ print FNR > new }
END { saveChanges() }

function saveChanges(   bak, result, mkBackup, overwriteOrig, rmBackup) {
    if ( new != "" ) {
        bak = old ".bak"
        mkBackup = "cp \047" old "\047 \047" bak "\047; echo \"$?\""
        if ( (mkBackup | getline result) > 0 ) {
            if (result == 0) {
                overwriteOrig = "mv \047" new "\047 \047" old "\047; echo \"$?\""
                if ( (overwriteOrig | getline result) > 0 ) {
                    if (result == 0) {
                        rmBackup = "rm -f \047" bak "\047"
                        system(rmBackup)
                    }
                }
            }
        }
        close(rmBackup)
        close(overwriteOrig)
        close(mkBackup)
    }
    old = FILENAME
    new = FILENAME ".new"
}

$ awk -f ../tst.awk test1.txt test2.txt test3.txt

আমি প্রথমে ব্যাকআপে মূল ফাইলটি অনুলিপি করতে পছন্দ করেছি এবং তারপরে মূল সংরক্ষণের পরিবর্তনগুলি পরিচালনা করেছিলাম তবে এটি করার ফলে প্রতিটি ইনপুট ফাইলের ফাইল ফাইলের ভেরিয়েবলের মান বদলে যায় যা অনাকাঙ্ক্ষিত।

মনে রাখবেন যে আপনার যদি নামের সাথে একটি আসল ফাইল থাকে whatever.bakবা whatever.newআপনার ডিরেক্টরিতে থাকে তবে আপনি সেগুলি অস্থায়ী ফাইলগুলি দিয়ে ওভাররাইট করতে চান তাই আপনারও এটির জন্য একটি পরীক্ষা যুক্ত করতে হবে। mktempটেম্প ফাইল ফাইল পেতে একটি কল আরও শক্তিশালী হবে।

এই পরিস্থিতিতে আরও বেশি কার্যকর জিনিস হ'ল এমন একটি সরঞ্জাম যা অন্য কোনও কমান্ড কার্যকর করে এবং "ইনপ্লেস" সম্পাদনা অংশটি কাজ করে যেহেতু পসিক্স সেড, আর্ক, গ্রেপ, ত্রি, যাই হোক না কেন এবং "ইনপ্লেস" সম্পাদনা সরবরাহ করতে পারে and আপনি print > outযখনই কোনও মান মুদ্রণ করতে চান তখন আপনাকে আপনার স্ক্রিপ্টের বাক্য গঠনটি পরিবর্তন করতে হবে না । একটি সাধারণ, ভঙ্গুর উদাহরণ:

$ cat inedit
#!/bin/env bash

for (( pos=$#; pos>1; pos-- )); do
    if [[ -f "${!pos}" ]]; then
        filesStartPos="$pos"
    else
        break
    fi
done

files=()
cmd=()
for (( pos=1; pos<=$#; pos++)); do
    arg="${!pos}"
    if (( pos < filesStartPos )); then
        cmd+=( "$arg" )
    else
        files+=( "$arg" )
    fi
done

tmp=$(mktemp)
trap 'rm -f "$tmp"; exit' 0

for file in "${files[@]}"; do
    "${cmd[@]}" "$file" > "$tmp" && mv -- "$tmp" "$file"
done

যা আপনি নিম্নলিখিত হিসাবে ব্যবহার করতে চান:

$ awk '{print FNR}' test1.txt test2.txt test3.txt
1
2
1
2
1
2

$ ./inedit awk '{print FNR}' test1.txt test2.txt test3.txt

$ tail test1.txt test2.txt test3.txt
==> test1.txt <==
1
2

==> test2.txt <==
1
2

==> test3.txt <==
1
2

সেই ineditস্ক্রিপ্টের সাথে একটি স্পষ্ট সমস্যা হ'ল যখন আপনার একাধিক ইনপুট ফাইল থাকে তখন কমান্ড থেকে আলাদাভাবে ইনপুট / আউটপুট ফাইলগুলি সনাক্ত করা difficulty উপরের স্ক্রিপ্টটি ধরে নিয়েছে যে সমস্ত ইনপুট ফাইল কমান্ডের শেষে একটি তালিকা হিসাবে উপস্থিত হবে এবং কমান্ডটি তাদের বিরুদ্ধে একবারে চালিত হবে তবে অবশ্যই এর অর্থ আপনি এটি 2 বা ততোধিক ফাইলের জন্য স্ক্রিপ্টগুলির জন্য ব্যবহার করতে পারবেন না একটি সময়, যেমন:

awk 'NR==FNR{a[$1];next} $1 in a' file1 file2

বা স্ক্রিপ্টগুলি যা আরগ তালিকার ফাইলগুলির মধ্যে ভেরিয়েবল সেট করে, যেমন:

awk '{print $7}' FS=',' file1 FS=':' file2

এটিকে আরও দৃ xargsust়তর করে পাঠকের অনুশীলন হিসাবে রেখে দেওয়া, তবে শক্তিশালী কীভাবে ineditকাজ করতে হবে তার প্রাথমিক সূচনা হিসাবে সংক্ষেপে তাকান :-)।


0

শেল সমাধানটি সহজ এবং সম্ভবত যথেষ্ট দ্রুত:

for f in *.txt
do  awk '...' $f > $f.tmp
    mv $f.tmp $f
done

আপনি যদি নির্ধারিতভাবে দেখিয়েছেন যে এটি খুব ধীরগতির হয় তবে কেবলমাত্র একটি আলাদা সমাধান অনুসন্ধান করুন। মনে রাখবেন: অকালীন অপটিমাইজেশন হ'ল সমস্ত অশুভের মূল।


আপনার জবাবের জন্য আপনাকে ধন্যবাদ তবে আমার প্রশ্নে যেমন উল্লেখ করা হয়েছে আমরা নিজেই এই উত্তরটি সম্পর্কে সচেতন কিন্তু এটি এই কাজটি করার পক্ষে সত্যই একটি অতিমাত্রায় কাজ, এজন্য আমি উল্লেখ করেছি যে আমরা যদি কিছুটা ফাঁকে ফাঁকে ফাঁকে কিছু চেষ্টা করতে পারি তবে। আপনার সময় এবং ধন্যবাদ এখানে চিয়ার্সের জন্য আপনাকে ধন্যবাদ।
রবীন্দ্রসিংহ 13
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.