আপনি যদি লিনাক্স বা ম্যাক ব্যবহার করেন, তবে প্রতিবার টার্মিনাল খোলার সময় আপনি একটি শেল অ্যাপ্লিকেশন ব্যবহার করেন।
শেল হল একটি ইন্টারফেস যা আপনার সিস্টেমে কমান্ড চালাতে সাহায্য করে।
শেল পরিবেশ ভেরিয়েবল হোস্ট করে এবং কমান্ড ইতিহাস ও স্বয়ংসম্পূর্ণকরণ (auto-completion) जैसी उपयोगी বৈশিষ্ট্য প্রদান করে।
যদি আপনি জিনিসগুলো हुडের নিচে কীভাবে কাজ করে তা শিখতে পছন্দ করেন, তবে এই পোস্ট আপনার জন্য बिल्कুল সঠিক!
শেল কীভাবে কাজ করে?
আমাদের নিজস্ব শেল অ্যাপ্লিকেশন তৈরি করতে হলে চিন্তা করুন যে একটি শšel আসলে কী:
প্রথমে একটি প্রম্পট থাকে, সাধারণত বর্তমান ব্যবহারকারী ও বর্তমান ডিরেক্টরির মতো অতিরিক্ত তথ্যের সাথে, তারপর আপনি একটি কমান্ড টাইপ করেন এবং এন্টার চাপলে ফলাফল আপনার স্ক্রিনে প্রদর্শিত হয়।
হ্যাঁ, এটি খুবই বেসিক মনে হয়, কিন্তু কি এটি আপনাকে কিছু অন্য কিছু nhớ করায়?
যদি আপনি pry ভাবছেন, তবে আপনি সঠিক!
একটি শেল মূলত আপনার অপারেটিং সিস্টেমের জন্য একটি REPL (Read-Eval-Print-Loop)।
এটি জানা থাকলে আমরা আপনার শেলের প্রথম সংস্করণ লিখতে পারি:
prompt = "> " print prompt while (input = gets.chomp) break if input == "exit" system(input) print prompt end
এটি আমাদের একটি ন্যূনতম, কিন্তু কার্যকরী শেল দেবে। আমরা একটি লাইব্রেরি ব্যবহার করে এটি উন্নত করতে পারি যা অন্যান্য অনেক REPL-রূপ অ্যাপ্লিকেশন ব্যবহার করে।
उस লাইব্রেরির নাম Readline।
Readline লাইব্রেরি ব্যবহার করা
Readline রুবি স্ট্যান্ডার্ড লাইব্রেরির অংশ, তাই ইনস্টল করার কিছু নেই, শুধু require করলেই হবে।
Readline ব্যবহারের সুবিধাগুলোর মধ্যে একটি হল এটি স্বয়ংক্রিয়ভাবে কমান্ড ইতিহাস রাখতে পারে।
এটি কমান্ড প্রম্পট প্রিন্ট করা এবং অন্যান্য অনেক কাজও নিতে পারে।
এখানে আমাদের শেলের v2, এইবার Readline ব্যবহার করে:
require 'readline' while input = Readline.readline("> ", true) break if input == "exit" system(input) end
এটি দুটি puts প্রম্পটের জন্য দূর করেছে এবং এখন আমাদের Readline-এর কিছু শক্তিশালী ক্ষমতা পাওয়া যাচ্ছে। উদাহরণস্বরূপ, আমরা কীবোর্ড শর্টকাট ব্যবহার করে একটি শব্দ মুছে ফেলতে পারি (CTRL + W) বা ইতিহাস অনুসন্ধান করতে পারি (CTRL + R)!
আসুন পূর্ণ ইতিহাস প্রিন্ট করার জন্য একটি নতুন কমান্ড যোগ করি:
require 'readline' while input = Readline.readline("> ", true) break if input == "exit" puts Readline::HISTORY.to_a if input == "hist" # ইতিহাস থেকে খালি লাইন সরান Readline::HISTORY.pop if input == "" system(input) end
মজার তথ্য: যদি আপনি এই কোডটি pry-তে চেষ্টা করেন, তবে আপনি pry-এর কমান্ড ইতিহাস পাবেন! কারণ pryও
Readlineব্যবহার করে, এবংReadline::HISTORYশেয়ার্ড স্টেট।
এখন আপনি hist টাইপ করে আপনার কমান্ড ইতিহাস পেতে পারেন 🙂
স্বয়ংসম্পূর্ণকরণ (Auto-Completion) যোগ করা
আপনার প্রিয় শেলের স্বয়ংসম্পূর্ণকরণ বৈশিষ্ট্যের কারণে আপনি অনেক টাইপিং বাঁচাতে পারেন। Readline এই বৈশিষ্ট্যকে আপনার শেলে একীভূত করা খুব সহজ করে দেয়।
আমাদের ইতিহাস থেকে কমান্ড স্বয়ংসম্পূর্ণকরণ দিয়ে শুরু করি।
উদাহরণ:
comp = proc { |s| Readline::HISTORY.grep(/^#{Regexp.escape(s)}/) } Readline.completion_append_character = " " Readline.completion_proc = comp ## বাকি কোড এখানে যাবে ##
এই কোডের সাথে আপনি <tab> কী চাপলে পূর্বে টাইপ করা কমান্ডগুলো স্বয়ংসম্পূর্ণ করতে পারবেন। এখন এক ধাপ এগিয়ে ডিরেক্টরি স্বয়ংসম্পূর্ণকরণ যোগ করি।
উদাহরণ:
comp = proc do |s| directory_list = Dir.glob("#{s}*") if directory_list.size > 0 directory_list else Readline::HISTORY.grep(/^#{Regexp.escape(s)}/) end end
completion_proc সম্ভাব্য кандидаদের তালিকা ফেরত দেয়, এই ক্ষেত্রে আমাদের শুধু চেক করতে হবে টাইপ করা স্ট্রিং ডিরেক্টরি নামের অংশ কিনা Dir.glob ব্যবহার করে। Readline বাকি বিষয়গুলো নিবে!
System মেথড বাস্তবায়ন করা
এখন আপনার কাছে ইতিহাস ও স্বয়ংসম্পূর্ণকরণ সহ একটি কাজ করানো শেল আছে, ২৫ লাইন কোডের জন্য খারাপ না 🙂
কিন্তু একটা বিষয় আছে যা আমি গভীরে যেতে চাই, যাতে আপনি কমান্ড এক্সিকিউশনের পিছনের দৃশ্য বুঝতে পারেন।
এটি system মেথড দ্বারা করা হয়, C-এ এই মেথড আপনার কমান্ডকে /bin/sh-এ পাঠায়, যা একটি শেল অ্যাপ্লিকেশন। চলুন দেখি /bin/sh কী করে সেটি রুবিতে কীভাবে বাস্তবায়ন করা যায়।
নোট: এটি শুধু লিনাক্স/ম্যাক-এ কাজ করবে 🙂
system মেথড:
def system(command) fork { exec(command) } end
এখানে fork বর্তমান প্রসেসের একটি নতুন কপি তৈরি করে, তারপর এই প্রসেসটি exec মেথডের মাধ্যমে আমাদের চাওয়া কমান্ড দ্বারা প্রতিস্থাপিত হয়। এটি লিনাক্স প্রোগ্রামিং-এ একটি খুব সাধারণ প্যাটার্ন।
আপনি যদি fork না করেন তবে বর্তমান প্রসেসই প্রতিস্থাপিত হবে, অর্থাৎ আপনি যে কমান্ড চালাচ্ছেন (ls, cd বা অন্য যেকোনো কিছু) শেষ হলে আপনার রুবি প্রোগ্রামও সাথেই টার্মিনেট হবে।
আপনি এখানে তা দেখতে পারেন:
def system(command) exec(command) end system('ls') # এই কোড কখনো চলবে না! puts "after system"
উপসংহার
এই পোস্টে আপনি শিখলেন যে একটি শেল একটি REPL-রূপ ইন্টারফেস (সোচ্চার irb / pry) আপনার সিস্টেমের সাথে ইন্টারঅ্যাক্ট করার জন্য। আপনি বَلِয়শালী Readline লাইব্রেরি ব্যবহার করে নিজের শেল কীভাবে বানাতে হয় তা শিখলেন, যা ইতিহাস ও স্বয়ংসম্পূর্ণকরণের মতো অনেক বিল্ট-ইন বৈশিষ্ট্য প্রদান করে (কিন্তু আপনাকে সংজ্ঞায়িত করতে হবে সেটি কীভাবে কাজ করবে)।
তারপর আপনি লিনাক্স প্রোগ্রামিং প্রকল্পে সাধারণত ব্যবহৃত fork + exec প্যাটার্ন সম্পর্কে শিখলেন।
যদি এই পোস্টটি আপনার ভালো লাগে, তবে আপনার সব রুবি বন্ধুদের সাথে শেয়ার করবেন? এটি ব্লগ বাড়াতে সাহায্য করবে এবং অধিক মানুষ শিখতে পারবে 🙂