কম্পিউটার

আপনি ব্যাশ জানেন না:ব্যাশ অ্যারেগুলির একটি ভূমিকা

যদিও সফ্টওয়্যার প্রকৌশলীরা নিয়মিতভাবে বিকাশের বিভিন্ন দিকের জন্য কমান্ড লাইন ব্যবহার করেন, অ্যারে সম্ভবত কমান্ড লাইনের আরও অস্পষ্ট বৈশিষ্ট্যগুলির মধ্যে একটি (যদিও তা নয় রেজেক্স অপারেটর =~ হিসাবে অস্পষ্ট ) কিন্তু অস্পষ্টতা এবং প্রশ্নবিদ্ধ সিনট্যাক্স বাদ দিয়ে, ব্যাশ অ্যারে খুব শক্তিশালী হতে পারে।

অপেক্ষা কর, কিন্তু কেন?

ব্যাশ সম্পর্কে লেখা চ্যালেঞ্জিং কারণ একটি নিবন্ধের জন্য সিনট্যাক্সের অদ্ভুততার উপর ফোকাস করে এমন একটি ম্যানুয়াল তৈরি করা অসাধারণভাবে সহজ। নিশ্চিন্ত থাকুন, যাইহোক, এই নিবন্ধটির উদ্দেশ্য হল আপনাকে RTFM এড়ানো।

একটি বাস্তব (আসলে দরকারী) উদাহরণ

সেই লক্ষ্যে, আসুন একটি বাস্তব-বিশ্বের পরিস্থিতি বিবেচনা করি এবং কীভাবে বাশ সাহায্য করতে পারে:আপনি আপনার অভ্যন্তরীণ ডেটা পাইপলাইনের রানটাইম মূল্যায়ন এবং অপ্টিমাইজ করার জন্য আপনার কোম্পানিতে একটি নতুন প্রচেষ্টার নেতৃত্ব দিচ্ছেন। প্রথম ধাপ হিসেবে, পাইপলাইন কতটা ভালোভাবে থ্রেড ব্যবহার করে তা মূল্যায়ন করতে আপনি একটি প্যারামিটার সুইপ করতে চান। সরলতার স্বার্থে, আমরা পাইপলাইনটিকে একটি সংকলিত C++ ব্ল্যাক বক্স হিসাবে বিবেচনা করব যেখানে শুধুমাত্র প্যারামিটারটি আমরা টুইক করতে পারি তা হল ডেটা প্রক্রিয়াকরণের জন্য সংরক্ষিত থ্রেডের সংখ্যা:./pipeline --threads 4 .

মূল বিষয়গুলি

আমরা প্রথমে যা করব তা হল --threads-এর মান ধারণকারী একটি অ্যারে সংজ্ঞায়িত করা প্যারামিটার যা আমরা পরীক্ষা করতে চাই:

allThreads=(1 2 4 8 16 32 64 128)

এই উদাহরণে, সমস্ত উপাদান সংখ্যা, কিন্তু এটির ক্ষেত্রে এটির প্রয়োজন নেই—ব্যাশের অ্যারেগুলিতে সংখ্যা এবং স্ট্রিং উভয়ই থাকতে পারে, যেমন, myArray=(1 2 "three" 4 "five") একটি বৈধ অভিব্যক্তি। এবং অন্য যেকোন ব্যাশ ভেরিয়েবলের মতোই, নিশ্চিত করুন যেন সমান চিহ্নের চারপাশে কোনো ফাঁকা জায়গা না থাকে। অন্যথায়, ব্যাশ ভেরিয়েবলের নামটিকে কার্যকর করার জন্য একটি প্রোগ্রাম হিসাবে বিবেচনা করবে এবং = এর প্রথম প্যারামিটার হিসেবে!

এখন আমরা অ্যারে শুরু করেছি, এর কয়েকটি উপাদান পুনরুদ্ধার করা যাক। আপনি লক্ষ্য করবেন যে শুধুমাত্র echo $allThreads করছেন শুধুমাত্র প্রথম উপাদান আউটপুট করবে।

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

type="article"
echo "Found 42 $type"

ভেরিয়েবল $type বলুন একটি একবচন বিশেষ্য হিসাবে আমাদের দেওয়া হয় এবং আমরা একটি s যোগ করতে চাই আমাদের বাক্যের শেষে। আমরা কেবল একটি s যোগ করতে পারি না $type-এ যেহেতু এটি একটি ভিন্ন ভেরিয়েবলে পরিণত হবে, $types . এবং যদিও আমরা echo "Found 42 "$type"s" এর মতো কোড কনটরশন ব্যবহার করতে পারি , এই সমস্যা সমাধানের সর্বোত্তম উপায় হল কোঁকড়া ধনুর্বন্ধনী ব্যবহার করা:echo "Found 42 ${type}s" , যা আমাদের Bash কে বলতে দেয় যে একটি ভেরিয়েবলের নাম কোথায় শুরু হয় এবং শেষ হয় (আশ্চর্যজনকভাবে, এটি একই সিনট্যাক্স যা JavaScript/ES6 এ ভেরিয়েবল এবং এক্সপ্রেশনগুলিকে টেমপ্লেট লিটারেলে ইনজেক্ট করতে ব্যবহৃত হয়)।

সুতরাং এটি সক্রিয় আউট, যদিও Bash ভেরিয়েবলের সাধারণত কোঁকড়া বন্ধনী প্রয়োজন হয় না, তারা অ্যারের জন্য প্রয়োজন. পরিবর্তে, এটি আমাদের অ্যাক্সেস করার জন্য সূচক নির্দিষ্ট করতে দেয়, যেমন, echo ${allThreads[1]} অ্যারের দ্বিতীয় উপাদান প্রদান করে। বন্ধনী সহ নয়, যেমন,echo $allThreads[1] , ব্যাশকে [1]-এর চিকিৎসা করতে নিয়ে যায় একটি স্ট্রিং হিসাবে এবং এটি যেমন আউটপুট।

হ্যাঁ, ব্যাশ অ্যারেগুলির অদ্ভুত সিনট্যাক্স রয়েছে, তবে অন্তত সেগুলি শূন্য-সূচীযুক্ত, অন্য কিছু ভাষার বিপরীতে (আমি আপনাকে দেখছি, R )।

অ্যারেগুলির মাধ্যমে লুপ করা

যদিও উপরের উদাহরণগুলিতে আমরা আমাদের অ্যারেতে পূর্ণসংখ্যা সূচক ব্যবহার করেছি, আসুন দুটি উপলক্ষ বিবেচনা করি যখন এটি হবে না:প্রথমত, যদি আমরা $i চাই অ্যারের -তম উপাদান, যেখানে $i আগ্রহের সূচক ধারণকারী একটি পরিবর্তনশীল, আমরা এই উপাদানটি ব্যবহার করে পুনরুদ্ধার করতে পারি:echo ${allThreads[$i]} . দ্বিতীয়ত, একটি অ্যারের সমস্ত উপাদান আউটপুট করতে, আমরা সাংখ্যিক সূচকটিকে @ দিয়ে প্রতিস্থাপন করি। প্রতীক (আপনি @ ভাবতে পারেন all এর জন্য দাঁড়ানো হিসাবে ):echo ${allThreads[@]} .

অ্যারে উপাদানগুলির মাধ্যমে লুপ করা

এটি মাথায় রেখে, আসুন $allThreads এর মাধ্যমে লুপ করি এবং --threads-এর প্রতিটি মানের জন্য পাইপলাইন চালু করুন :

for t in ${allThreads[@]}; do
  ./pipeline --threads $t
done

অ্যারে সূচকের মাধ্যমে লুপ করা

এর পরে, আসুন একটু ভিন্ন পদ্ধতি বিবেচনা করা যাক। অ্যারে উপাদানের উপর লুপ করার পরিবর্তে , আমরা অ্যারে সূচক লুপ করতে পারি :

for i in ${!allThreads[@]}; do
  ./pipeline --threads ${allThreads[$i]}
done

আসুন এটি ভেঙে ফেলা যাক:আমরা উপরে যেমন দেখেছি, ${allThreads[@]} আমাদের অ্যারের সমস্ত উপাদান উপস্থাপন করে। এটিকে ${!allThreads[@]} করতে একটি বিস্ময় চিহ্ন যোগ করা হচ্ছে সমস্ত অ্যারের সূচকের তালিকা ফিরিয়ে দেবে (আমাদের ক্ষেত্রে 0 থেকে 7)। অন্য কথায়, for লুপ সমস্ত সূচক $i দিয়ে লুপ করছে এবং $i পড়ছে $allThreads থেকে -তম উপাদান --threads এর মান সেট করতে প্যারামিটার।

এটি চোখের উপর অনেক বেশি কঠোর, তাই আপনি ভাবছেন কেন আমি প্রথমে এটি চালু করতে বিরক্ত করছি। কারণ এমন কিছু সময় আছে যেখানে আপনাকে একটি লুপের মধ্যে সূচক এবং মান উভয়ই জানতে হবে, যেমন, আপনি যদি অ্যারের প্রথম উপাদানটিকে উপেক্ষা করতে চান, তাহলে সূচকগুলি ব্যবহার করা আপনাকে একটি অতিরিক্ত ভেরিয়েবল তৈরি করা থেকে বাঁচায় যা আপনি লুপের ভিতরে বাড়ান। .

পপুলেটিং অ্যারে

এখন পর্যন্ত, আমরা প্রতিটি --threads-এর জন্য পাইপলাইন চালু করতে সক্ষম হয়েছি সুদ. এখন, ধরা যাক আমাদের পাইপলাইনের আউটপুট সেকেন্ডে রানটাইম। আমরা প্রতিটি পুনরাবৃত্তিতে সেই আউটপুটটি ক্যাপচার করতে চাই এবং এটিকে অন্য অ্যারেতে সংরক্ষণ করতে চাই যাতে আমরা শেষে এটির সাথে বিভিন্ন ম্যানিপুলেশন করতে পারি।

কিছু ​​দরকারী বাক্য গঠন

কিন্তু কোডে ডুব দেওয়ার আগে, আমাদের আরও কিছু সিনট্যাক্স প্রবর্তন করতে হবে। প্রথমত, আমাদের একটি Bash কমান্ডের আউটপুট পুনরুদ্ধার করতে সক্ষম হতে হবে। এটি করতে, নিম্নলিখিত সিনট্যাক্স ব্যবহার করুন:output=$( ./my_script.sh ) , যা আমাদের কমান্ডের আউটপুট ভেরিয়েবল $output এ সংরক্ষণ করবে .

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

myArray+=( "newElement1" "newElement2" )

প্যারামিটার সুইপ

সবকিছু একসাথে রেখে, এখানে আমাদের প্যারামিটার সুইপ চালু করার জন্য আমাদের স্ক্রিপ্ট রয়েছে:

allThreads=(1 2 4 8 16 32 64 128)
allRuntimes=()
for t in ${allThreads[@]}; do
  runtime=$(./pipeline --threads $t)
  allRuntimes+=( $runtime )
done

এবং voilà!

আপনি আর কি পেয়েছেন?

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

লগ সতর্কতা

এই পরিস্থিতিতে, আপনার অ্যাপটি মডিউলে বিভক্ত, প্রতিটির নিজস্ব লগ ফাইল রয়েছে। নির্দিষ্ট মডিউলে সমস্যার লক্ষণ থাকলে সঠিক ব্যক্তিকে ইমেল করার জন্য আমরা একটি ক্রোন কাজের স্ক্রিপ্ট লিখতে পারি:

# List of logs and who should be notified of issues
logPaths=("api.log" "auth.log" "jenkins.log" "data.log")
logEmails=("jay@email" "emma@email" "jon@email" "sophia@email")

# Look for signs of trouble in each log
for i in ${!logPaths[@]};
do
  log=${logPaths[$i]}
  stakeholder=${logEmails[$i]}
  numErrors=$( tail -n 100 "$log" | grep "ERROR" | wc -l )

  # Warn stakeholders if recently saw > 5 errors
  if [[ "$numErrors" -gt 5 ]];
  then
    emailRecipient="$stakeholder"
    emailSubject="WARNING: ${log} showing unusual levels of errors"
    emailBody="${numErrors} errors found in log ${log}"
    echo "$emailBody" | mailx -s "$emailSubject" "$emailRecipient"
  fi
done

API প্রশ্নগুলি

বলুন আপনি এমন কিছু বিশ্লেষণ তৈরি করতে চান যেগুলি সম্পর্কে ব্যবহারকারীরা আপনার মিডিয়াম পোস্টগুলিতে সবচেয়ে বেশি মন্তব্য করে৷ যেহেতু আমাদের সরাসরি ডাটাবেস অ্যাক্সেস নেই, তাই এসকিউএল প্রশ্নটির বাইরে, কিন্তু আমরা API ব্যবহার করতে পারি!

API প্রমাণীকরণ এবং টোকেন সম্পর্কে দীর্ঘ আলোচনা এড়াতে, আমরা এর পরিবর্তে JSONPlaceholder, একটি পাবলিক-ফেসিং API টেস্টিং পরিষেবা, আমাদের শেষ পয়েন্ট হিসাবে ব্যবহার করব। একবার আমরা প্রতিটি পোস্টকে জিজ্ঞাসা করি এবং যারা মন্তব্য করেছেন তাদের ইমেলগুলি পুনরুদ্ধার করি, আমরা সেই ইমেলগুলিকে আমাদের ফলাফল অ্যারেতে যুক্ত করতে পারি:

endpoint="https://jsonplaceholder.typicode.com/comments"
allEmails=()

# Query first 10 posts
for postId in {1..10};
do
  # Make API call to fetch emails of this posts's commenters
  response=$(curl "${endpoint}?postId=${postId}")

  # Use jq to parse the JSON response into an array
  allEmails+=( $( jq '.[].email' <<< "$response" ) )
done

এখানে নোট করুন যে আমি jq ব্যবহার করছি কমান্ড লাইন থেকে JSON পার্স করার টুল। jq এর সিনট্যাক্স এই নিবন্ধের সুযোগের বাইরে, তবে আমি আপনাকে এটি দেখার সুপারিশ করছি৷

আপনি যেমন কল্পনা করতে পারেন, এমন অসংখ্য অন্যান্য পরিস্থিতি রয়েছে যেখানে ব্যাশ অ্যারে ব্যবহার করে সাহায্য করতে পারে, এবং আমি আশা করি এই নিবন্ধে বর্ণিত উদাহরণগুলি আপনাকে চিন্তার জন্য কিছু খাবার দিয়েছে। আপনার নিজের কাজ থেকে শেয়ার করার জন্য আপনার কাছে অন্য উদাহরণ থাকলে, অনুগ্রহ করে নীচে একটি মন্তব্য করুন৷

কিন্তু অপেক্ষা করুন, আরও আছে!

যেহেতু আমরা এই নিবন্ধে বেশ খানিকটা অ্যারে সিনট্যাক্স কভার করেছি, তাই এখানে আমরা যা কভার করেছি তার একটি সারসংক্ষেপ, এর সাথে আরও কিছু উন্নত কৌশল যা আমরা কভার করিনি:

সিনট্যাক্স ফলাফল
arr=() একটি খালি অ্যারে তৈরি করুন
arr=(1 2 3) অ্যারে শুরু করুন
${arr[2]} তৃতীয় উপাদান পুনরুদ্ধার করুন
${arr[@]} সমস্ত উপাদান পুনরুদ্ধার করুন
${!arr[@]} অ্যারে সূচক পুনরুদ্ধার করুন
${#arr[@]} অ্যারের আকার গণনা করুন
arr[0]=3 ১ম উপাদান ওভাররাইট করুন
arr+=(4) মান যোগ করুন
str=$(ls) ls সংরক্ষণ করুন একটি স্ট্রিং হিসাবে আউটপুট
arr=( $(ls) ) ls সংরক্ষণ করুন ফাইলের অ্যারে হিসাবে আউটপুট
${arr[@]:s:n} n উপাদানগুলি পুনরুদ্ধার করুন starting at index s

একটি শেষ চিন্তা

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

ব্যাশ নাকি পাইথন?

কোনটি প্রশ্ন জাগে:পাইথনের মতো অন্যান্য স্ক্রিপ্টিং ভাষার পরিবর্তে আপনার কখন ব্যাশ অ্যারে ব্যবহার করা উচিত?

আমার কাছে, এটি সমস্ত নির্ভরতার উপর ফোঁড়া- যদি আপনি শুধুমাত্র কমান্ড-লাইন সরঞ্জামগুলিতে কলগুলি ব্যবহার করে সমস্যার সমাধান করতে পারেন তবে আপনি ব্যাশও ব্যবহার করতে পারেন। কিন্তু যখন আপনার স্ক্রিপ্ট একটি বৃহত্তর পাইথন প্রকল্পের অংশ হয়, তখন আপনি পাইথনও ব্যবহার করতে পারেন।

উদাহরণ স্বরূপ, আমরা প্যারামিটার সুইপ বাস্তবায়নের জন্য পাইথনে যেতে পারতাম, কিন্তু আমরা ব্যাশের চারপাশে একটি মোড়ক লিখে শেষ করতাম:

import subprocess

all_threads = [1, 2, 4, 8, 16, 32, 64, 128]
all_runtimes = []

# Launch pipeline on each number of threads
for t in all_threads:
  cmd = './pipeline --threads {}'.format(t)

  # Use the subprocess module to fetch the return output
  p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
  output = p.communicate()[0]
  all_runtimes.append(output)

যেহেতু এই উদাহরণে কমান্ড লাইনের আশেপাশে কোন স্থান নেই, তাই সরাসরি ব্যাশ ব্যবহার করা বাঞ্ছনীয়।

একটি নির্লজ্জ প্লাগের জন্য সময়

এই নিবন্ধটি আমি OSCON এ দেওয়া একটি বক্তৃতার উপর ভিত্তি করে, যেখানে আমি লাইভ-কোডিং কর্মশালা উপস্থাপন করেছি You Don't Know Bash . কোনো স্লাইড নেই, কোনো ক্লিকার নেই—শুধু আমি এবং শ্রোতারা কমান্ড লাইনে টাইপ করছি, ব্যাশের বিস্ময়কর জগতকে অন্বেষণ করছি।


  1. ব্লুটুথ 5.1:আপনার যা কিছু জানা দরকার

  2. Android 10:আপনার যা জানা দরকার

  3. 5 ইউএসবি ড্রাইভের ব্যবহার যা আপনি সম্ভবত জানেন না

  4. Wi-Fi 6:আপনার যা জানা দরকার!