আমি কোনও প্যাটার্নের জন্য কোনও ফাইল (বা ফাইলগুলির তালিকা) অনুসন্ধান করার জন্য একটি স্ক্রিপ্ট খুঁজছি এবং যদি পাওয়া যায় তবে সেই মানটিকে একটি নির্দিষ্ট মান দিয়ে প্রতিস্থাপন করব।
থটস?
আমি কোনও প্যাটার্নের জন্য কোনও ফাইল (বা ফাইলগুলির তালিকা) অনুসন্ধান করার জন্য একটি স্ক্রিপ্ট খুঁজছি এবং যদি পাওয়া যায় তবে সেই মানটিকে একটি নির্দিষ্ট মান দিয়ে প্রতিস্থাপন করব।
থটস?
উত্তর:
অস্বীকৃতি: এই পদ্ধতিটি রুবির ক্ষমতার একটি নিখুঁত চিত্র, এবং ফাইলগুলিতে স্ট্রিং প্রতিস্থাপনের জন্য উত্পাদন-গ্রেড সমাধান নয়। এটি বিভিন্ন ব্যর্থতার পরিস্থিতিতে যেমন ক্রাশ, বিঘ্নিত বা ডিস্ক পূর্ণ হওয়ার ক্ষেত্রে ডেটা হারাতে পারে। এই কোডটি দ্রুত ওয়ান-অফ স্ক্রিপ্টের বাইরে এমন কোনও কিছুর জন্য উপযুক্ত নয় যেখানে সমস্ত ডেটা ব্যাক আপ হয়। যে কারণে, আপনার প্রোগ্রামগুলিতে এই কোডটি অনুলিপি করবেন না।
এটি করার জন্য এখানে একটি দ্রুত সংক্ষিপ্ত উপায়।
file_names = ['foo.txt', 'bar.txt']
file_names.each do |file_name|
text = File.read(file_name)
new_contents = text.gsub(/search_regexp/, "replacement string")
# To merely print the contents of the file, use:
puts new_contents
# To write changes to the file, use:
File.open(file_name, "w") {|file| file.puts new_contents }
end
File.write(file_name, text.gsub(/regexp/, "replace")
প্রকৃতপক্ষে, রুবিতে একটি জায়গা-তে সম্পাদনা বৈশিষ্ট্য রয়েছে। পার্লের মতো, আপনি বলতে পারেন
ruby -pi.bak -e "gsub(/oldtext/, 'newtext')" *.txt
এটি বর্তমান ডিরেক্টরিতে সমস্ত ফাইলের ডাবল-কোটে কোড প্রয়োগ করবে যার নাম ".txt" দিয়ে শেষ হবে। সম্পাদিত ফাইলগুলির ব্যাকআপ অনুলিপি একটি ".bak" এক্সটেনশন ("foobar.txt.bak" আমার মনে হয়) দিয়ে তৈরি করা হবে।
দ্রষ্টব্য: এটি বহু লাইন অনুসন্ধানের জন্য কাজ করে না বলে মনে হচ্ছে। তাদের জন্য, আপনাকে এটিকে আরও কম সুন্দর উপায়ে করতে হবে, রেজেসের চারপাশে মোড়ক স্ক্রিপ্ট সহ।
<main>': undefined method
gsub ' in the main: অবজেক্ট (NoMethodError)
-i
সম্পাদনা করে। .bak
ব্যাকআপ ফাইলের জন্য ব্যবহৃত এক্সটেনশন (alচ্ছিক)। -p
ভালো কিছু হয় while gets; <script>; puts $_; end
। ( $_
সর্বশেষ পঠিত লাইন, তবে আপনি এর মতো echo aa | ruby -p -e '$_.upcase!'
মনে রাখবেন যে, আপনি যখন এটি করেন, ফাইল সিস্টেমটি জায়গার বাইরে চলে যেতে পারে এবং আপনি একটি শূন্য দৈর্ঘ্যের ফাইল তৈরি করতে পারেন। সিস্টেম কনফিগারেশন পরিচালনার অংশ হিসাবে আপনি যদি / etc / passwd ফাইলগুলি লেখার মতো কিছু করে থাকেন তবে এটি বিপর্যয়কর।
নোট করুন যে স্থানটিতে থাকা ফাইল সম্পাদনা গ্রহণযোগ্য উত্তরের মতো সর্বদা ফাইলটি কেটে ফেলা হবে এবং ক্রমান্বয়ে নতুন ফাইলটি লিখবে। সর্বদা একটি দৌড়ের শর্ত থাকবে যেখানে সহবর্তী পাঠকরা একটি বিচ্ছিন্ন ফাইল দেখতে পাবেন। প্রক্রিয়াটি যদি লেখার সময় কোনও কারণে (সিটিআরএল-সি, ওওএম কিলার, সিস্টেম ক্র্যাশ, বিদ্যুৎ বিভ্রাট ইত্যাদির জন্য) বাতিল হয়ে যায় তবে সংক্ষিপ্ত ফাইলটিও ছেড়ে দেওয়া হবে, যা বিপর্যয়কর হতে পারে। এটি ডেটালোস দৃশ্যের এক ধরণের যা বিকাশকারীদের বিবেচনা করা উচিত কারণ এটি ঘটবে। যে কারণে, আমি মনে করি গ্রহণযোগ্য উত্তরটি সম্ভবত গ্রহণযোগ্য উত্তর হওয়া উচিত নয়। খুব কম সময়ে একটি টেম্পাইল লিখুন এবং এই উত্তরের শেষে ফাইলটি "সরল" সমাধানের মতো জায়গায় নাম পরিবর্তন / নামকরণ করুন।
আপনার একটি অ্যালগরিদম ব্যবহার করা দরকার যা:
পুরানো ফাইল পড়ে এবং নতুন ফাইলটি লিখে দেয়। (পুরো ফাইলগুলিকে স্মৃতিতে স্লুপিং করা সম্পর্কে আপনাকে সতর্ক হওয়া দরকার)
স্পষ্টতই নতুন অস্থায়ী ফাইলটি বন্ধ করে দেয়, যেখানে আপনি কোনও ব্যতিক্রম ছুঁড়ে ফেলতে পারেন কারণ কোনও স্থান নেই বলে ফাইল বাফারগুলি ডিস্কে লেখা যায় না। (এটি ধরুন এবং যদি আপনি চান তবে অস্থায়ী ফাইলটি সাফ করুন, তবে আপনাকে কিছু পুনর্বিবেচনা করতে হবে বা এই মুহুর্তে মোটামুটি কঠোরভাবে ব্যর্থ হওয়া উচিত।
নতুন ফাইলে ফাইলের অনুমতি এবং মোডগুলি স্থির করে।
নতুন ফাইলটির নাম পরিবর্তন করে এটিকে জায়গায় ফেলে দেয়।
Ext3 ফাইল সিস্টেমে আপনার গ্যারান্টি রয়েছে যে ফাইলটি জায়গায় স্থানান্তরিত করতে মেটাডেটা রাইটিং ফাইল সিস্টেম দ্বারা পুনরায় সাজানো হবে না এবং নতুন ফাইলের জন্য ডেটা বাফার লেখার আগে এটি লিখিত হবে না, সুতরাং এটি সফল বা ব্যর্থ হওয়া উচিত। এক্সট 4 ফাইল সিস্টেমটিও এই জাতীয় আচরণকে সমর্থন করার জন্য প্যাচ করা হয়েছে। আপনি যদি খুব ভৌতিক fdatasync()
হয়ে থাকেন তবে ফাইলটি জায়গায় স্থানান্তরিত করার আগে আপনার কম্পিউটার কলটি ৩.৫ পদক্ষেপ হিসাবে কল করা উচিত।
ভাষা নির্বিশেষে, এটি সর্বোত্তম অনুশীলন। যে ভাষাগুলিতে কলিং close()
কোনও ব্যতিক্রম (পার্ল বা সি) ছুঁড়ে না ফেলে সেগুলিতে আপনাকে অবশ্যই স্পষ্টভাবে ফেরতটি যাচাই করতে হবে close()
এবং ব্যর্থ হলে ব্যতিক্রম ছুঁড়ে ফেলতে হবে।
কেবলমাত্র মেমরিতে ফাইল স্লার্প করতে, এটিকে ম্যানিপুলেট করুন এবং ফাইলটিতে লিখতে উপরের পরামর্শটি একটি পূর্ণ ফাইল সিস্টেমে শূন্য দৈর্ঘ্যের ফাইল তৈরির নিশ্চয়তা পাবে। সম্পূর্ণ লিখিত অস্থায়ী ফাইলটিকে জায়গায় স্থানান্তর করতে আপনার সর্বদা ব্যবহার FileUtils.mv
করা উচিত।
একটি চূড়ান্ত বিবেচনা হ'ল অস্থায়ী ফাইল স্থাপন করা। আপনি / টিএমপি-তে কোনও ফাইল খুললে আপনাকে কয়েকটি সমস্যা বিবেচনা করতে হবে:
যদি / টিএমপি অন্য কোনও ফাইল সিস্টেমে মাউন্ট করা থাকে তবে আপনি ফাইলটি লেখার আগে আপনি স্থান / টেম্প্প চালিয়ে যেতে পারেন যা অন্যথায় পুরানো ফাইলের গন্তব্যে মোতায়েনযোগ্য।
সম্ভবত আরও গুরুত্বপূর্ণ, আপনি যখন mv
কোনও ডিভাইস মাউন্ট জুড়ে ফাইলটি চেষ্টা করবেন আপনি স্বচ্ছভাবে cp
আচরণে রূপান্তরিত হবেন । পুরানো ফাইলটি খোলা হবে, পুরাতন ফাইলের ইনোড সংরক্ষণ এবং পুনরায় খোলা হবে এবং ফাইলের বিষয়বস্তু অনুলিপি করা হবে। এটি সম্ভবত আপনি যা চান তা নয়, এবং যদি আপনি চলমান ফাইলের বিষয়বস্তু সম্পাদনা করার চেষ্টা করেন তবে আপনি "টেক্সট ফাইল ব্যস্ত" ত্রুটিতে চলে যেতে পারেন। এটি ফাইল সিস্টেম mv
কমান্ডগুলি ব্যবহারের উদ্দেশ্যকেও পরাভূত করে এবং আপনি কেবলমাত্র একটি আংশিক লিখিত ফাইলের সাহায্যে গন্তব্য ফাইল সিস্টেমটি স্থানের বাইরে চালাতে পারেন।
রুবির বাস্তবায়নের সাথেও এর কোনও যোগসূত্র নেই। সিস্টেম mv
এবং cp
কমান্ড একই আচরণ করে।
এর চেয়ে বেশি পছন্দনীয় হ'ল পুরানো ফাইলের মতো একই ডিরেক্টরিতে একটি টেম্পফিল খোলা। এটি নিশ্চিত করে যে কোনও ক্রস-ডিভাইস সরানোর সমস্যা থাকবে না। mv
নিজেই ব্যর্থ না করা উচিত এবং আপনি সবসময় এমন একটি সম্পূর্ণ এবং untruncated ফাইল পাওয়া উচিত। যেকোন ব্যর্থতা যেমন স্থানের বাইরে ডিভাইস, অনুমতি ত্রুটি ইত্যাদি Temp টেম্পফিল লেখার সময় মুখোমুখি হওয়া উচিত।
গন্তব্য ডিরেক্টরিতে টেম্পফিল তৈরির পদ্ধতির একমাত্র ডাউনসাইডগুলি হ'ল:
এখানে কিছু কোড যা সম্পূর্ণ অ্যালগরিদম প্রয়োগ করে (উইন্ডোজ কোডটি অন্বেষিত এবং অসমাপ্ত):
#!/usr/bin/env ruby
require 'tempfile'
def file_edit(filename, regexp, replacement)
tempdir = File.dirname(filename)
tempprefix = File.basename(filename)
tempprefix.prepend('.') unless RUBY_PLATFORM =~ /mswin|mingw|windows/
tempfile =
begin
Tempfile.new(tempprefix, tempdir)
rescue
Tempfile.new(tempprefix)
end
File.open(filename).each do |line|
tempfile.puts line.gsub(regexp, replacement)
end
tempfile.fdatasync unless RUBY_PLATFORM =~ /mswin|mingw|windows/
tempfile.close
unless RUBY_PLATFORM =~ /mswin|mingw|windows/
stat = File.stat(filename)
FileUtils.chown stat.uid, stat.gid, tempfile.path
FileUtils.chmod stat.mode, tempfile.path
else
# FIXME: apply perms on windows
end
FileUtils.mv tempfile.path, filename
end
file_edit('/tmp/foo', /foo/, "baz")
এবং এখানে একটি সামান্য কঠোর সংস্করণ যা প্রতিটি সম্ভাব্য প্রান্তের মামলা সম্পর্কে চিন্তা করে না (যদি আপনি ইউনিক্সে থাকেন এবং / প্রোকে লেখার বিষয়ে চিন্তা করেন না):
#!/usr/bin/env ruby
require 'tempfile'
def file_edit(filename, regexp, replacement)
Tempfile.open(".#{File.basename(filename)}", File.dirname(filename)) do |tempfile|
File.open(filename).each do |line|
tempfile.puts line.gsub(regexp, replacement)
end
tempfile.fdatasync
tempfile.close
stat = File.stat(filename)
FileUtils.chown stat.uid, stat.gid, tempfile.path
FileUtils.chmod stat.mode, tempfile.path
FileUtils.mv tempfile.path, filename
end
end
file_edit('/tmp/foo', /foo/, "baz")
সত্যিই সরল ইউজ-কেস, যখন আপনি ফাইল সিস্টেমের অনুমতিগুলির বিষয়ে চিন্তা করেন না (হয় আপনি রুট হিসাবে চলছেন না, বা আপনি রুট হিসাবে চলছেন এবং ফাইলটি রুটের মালিকানাধীন):
#!/usr/bin/env ruby
require 'tempfile'
def file_edit(filename, regexp, replacement)
Tempfile.open(".#{File.basename(filename)}", File.dirname(filename)) do |tempfile|
File.open(filename).each do |line|
tempfile.puts line.gsub(regexp, replacement)
end
tempfile.close
FileUtils.mv tempfile.path, filename
end
end
file_edit('/tmp/foo', /foo/, "baz")
টিএল; ডিআর : আপডেটটি পারমাণবিক এবং সমবর্তী পাঠকরা সংক্ষিপ্ত ফাইলগুলি দেখতে পাবে না তা নিশ্চিত করার জন্য সর্বনিম্ন স্বীকৃত উত্তরের পরিবর্তে এটি ব্যবহার করা উচিত। আমি উপরে উল্লিখিত হিসাবে, সম্পাদিত ফাইল হিসাবে একই ডিরেক্টরিতে টেম্পফিল তৈরি করা এখানে জরুরী যাতে ক্রস ডিভাইস এমভি অপারেশনগুলি সিপি অপারেশনগুলিতে অনুবাদ করা যায় যদি / টিএমপি অন্য কোনও ডিভাইসে মাউন্ট করা থাকে। কল করা এফডিট্যাসেন্সিকে প্যারাওইয়ার একটি যুক্ত স্তর, তবে এটি একটি পারফরম্যান্স হিট করতে পারে, তাই এটি সাধারণত অনুশীলন না হওয়ায় আমি এই উদাহরণ থেকে বাদ দিয়েছি।
জায়গাগুলি ফাইল সম্পাদনা করার কোনও উপায় নেই isn't আপনি যখন এটির সাথে দূরে সরে যেতে পারেন তখন আপনি যা করেন (যেমন ফাইলগুলি খুব বড় না হয়) তা হ'ল, আপনি ফাইলটি মেমোরিতে পড়েন ( File.read
), পড়ার স্ট্রিংয়ে আপনার বিকল্পগুলি সম্পাদন করুন ( String#gsub
) এবং তারপরে পরিবর্তিত স্ট্রিংটি আবার লিখুন ফাইল ( File.open
, File#write
)।
আপনি ব্যবহার করতে পারেন - ফাইল বড় যথেষ্ট যে unfeasible হতে স্বরূপ, আপনি যা করতে হবে তা হন, অংশ ফাইলটি পড়ার (যদি প্যাটার্ন আপনি প্রতিস্থাপন করতে একাধিক লাইনের জুড়ে করা হবে না তারপর এক খণ্ড সাধারণত এক লাইন মানে চাই File.foreach
থেকে লাইন দ্বারা একটি ফাইল লাইন পড়ুন), এবং প্রতিটি অংশের জন্য এটি প্রতিস্থাপন সম্পাদন করুন এবং এটি একটি অস্থায়ী ফাইলের সাথে যুক্ত করুন। উত্স ফাইলটি পুনরাবৃত্তি করার পরে, আপনি এটি বন্ধ করে দিন এবং FileUtils.mv
অস্থায়ী ফাইলটির সাথে ওভাররাইট করার জন্য ব্যবহার করেন।
আরেকটি পদ্ধতি হ'ল রুবির অভ্যন্তরীণ সম্পাদনা ব্যবহার করা (কমান্ড লাইন থেকে নয়):
#!/usr/bin/ruby
def inplace_edit(file, bak, &block)
old_stdout = $stdout
argf = ARGF.clone
argf.argv.replace [file]
argf.inplace_mode = bak
argf.each_line do |line|
yield line
end
argf.close
$stdout = old_stdout
end
inplace_edit 'test.txt', '.bak' do |line|
line = line.gsub(/search1/,"replace1")
line = line.gsub(/search2/,"replace2")
print line unless line.match(/something/)
end
আপনি যদি ব্যাকআপ তৈরি করতে না চান তবে এতে পরিবর্তন '.bak'
করুন ''
।
read
ফাইলটি স্লার্প করার চেষ্টা করার চেয়ে এটি আরও ভাল । এটি স্কেলযোগ্য এবং খুব দ্রুত হওয়া উচিত।
এটি আমার পক্ষে কাজ করে:
filename = "foo"
text = File.read(filename)
content = text.gsub(/search_regexp/, "replacestring")
File.open(filename, "w") { |file| file << content }
প্রদত্ত ডিরেক্টরিতে সমস্ত ফাইল সন্ধান / প্রতিস্থাপনের জন্য এখানে একটি সমাধান রয়েছে। মূলত আমি সেপ 2 কে প্রদত্ত উত্তর নিয়েছি এবং এটি প্রসারিত করেছি।
# First set the files to search/replace in
files = Dir.glob("/PATH/*")
# Then set the variables for find/replace
@original_string_or_regex = /REGEX/
@replacement_string = "STRING"
files.each do |file_name|
text = File.read(file_name)
replace = text.gsub!(@original_string_or_regex, @replacement_string)
File.open(file_name, "w") { |file| file.puts replace }
end
require 'trollop'
opts = Trollop::options do
opt :output, "Output file", :type => String
opt :input, "Input file", :type => String
opt :ss, "String to search", :type => String
opt :rs, "String to replace", :type => String
end
text = File.read(opts.input)
text.gsub!(opts.ss, opts.rs)
File.open(opts.output, 'w') { |f| f.write(text) }
আপনার যদি লাইন সীমানা জুড়ে বিকল্পগুলি করতে হয়, তবে ব্যবহার করা কার্যকর ruby -pi -e
হবে না কারণ p
প্রক্রিয়াগুলি একবারে এক লাইন প্রসেস করে। পরিবর্তে, আমি নিম্নলিখিতটি সুপারিশ করি, যদিও এটি মাল্টি-জিবি ফাইলের সাথে ব্যর্থ হতে পারে:
ruby -e "file='translation.ja.yml'; IO.write(file, (IO.read(file).gsub(/\s+'$/, %q('))))"
একটি শব্দের পরে শ্বেত স্থান (সম্ভাব্য নতুন লাইনগুলি সহ) অনুসন্ধান করা হচ্ছে, সেক্ষেত্রে এটি সাদা স্থান থেকে মুক্তি পাবে। %q(')
উদ্ধৃতি চরিত্র উদ্ধৃত শুধু একটি অভিনব উপায়।
এখানে স্ক্রিপ্টে জিম থেকে এক লাইনারের বিকল্প
ARGV[0..-3].each{|f| File.write(f, File.read(f).gsub(ARGV[-2],ARGV[-1]))}
এটি কোনও স্ক্রিপ্টে সংরক্ষণ করুন, যেমন, edit.rb
আপনি কমান্ড লাইনে দিয়ে শুরু করুন
replace.rb *.txt <string_to_replace> <replacement>
* .txt অন্য নির্বাচন বা কিছু ফাইলের নাম বা পাথের সাথে প্রতিস্থাপন করা যেতে পারে
ভাঙ্গা যাতে আমি কী ঘটছে তা ব্যাখ্যা করতে পারি তবে এখনও কার্যকর হয়
# ARGV is an array of the arguments passed to the script.
ARGV[0..-3].each do |f| # enumerate the arguments of this script from the first to the last (-1) minus 2
File.write(f, # open the argument (= filename) for writing
File.read(f) # open the argument (= filename) for reading
.gsub(ARGV[-2],ARGV[-1])) # and replace all occurances of the beforelast with the last argument (string)
end
সম্পাদনা করুন: আপনি যদি নিয়মিত এক্সপ্রেশন ব্যবহার করতে চান তবে এর পরিবর্তে স্পষ্টতই, এটি কেবল তুলনামূলকভাবে ছোট পাঠ্য ফাইলগুলি পরিচালনা করার জন্য, কোনও গিগাবাইট দানব নয়
ARGV[0..-3].each{|f| File.write(f, File.read(f).gsub(/#{ARGV[-2]}/,ARGV[-1]))}
File.read
তা ব্যবহারের জন্য যে কোনও প্রস্তাবনাগুলি স্ট্যাকওভারফ্লো . com/a/25189286/128421 এ তথ্য দিয়ে মেজাজ করা দরকার । পরিবর্তেFile.open(filename, "w") { |file| file << content }
পরিবর্তনের পরিবর্তে ব্যবহার করুনFile.write(filename, content)
।