লু

লুপিং মধ্যে Bash

{one: "১টি অনুশীলনী", other: "%{count}টি অনুশীলনী"}

লুপিং সম্পর্কে

Bash-এ লুপ করার দুটি রূপ আছে:

  • আইটেমের একটি তালিকার প্রতিটি আইটেমের জন্য কিছু কমান্ড বারবার চালানো,
  • কোনো শর্ত ট্রু (বা ফলস) থাকা পর্যন্ত কিছু কমান্ড বারবার চালানো।

for লুপ

আইটেমের একটি তালিকার উপর ইটারেশন করতে আমরা for লুপ ব্যবহার করি।

for varname in words; do COMMANDS; done

words-কে word splitting ও filename expansion-এর মাধ্যমে সম্প্রসারিত করা হয় (যা আমরা কোটিং ধারণা-এ শিখেছি)। প্রতিটি শব্দ পালাক্রমে varname-এ অ্যাসাইন করা হয় এবং COMMANDS চালানো হয়।

নিচে কিছু উদাহরণ দেওয়া হলো, যেগুলো দেখায় কখন for লুপ কাজে লাগতে পারে

  • একগুচ্ছ ফাইলের উপর কিছু কমান্ড চালানো।

    # source all the bash library files in the current directory
    for file in ./*.bash; do
        source "$file"
    done
    
  • একটি স্ক্রিপ্ট বা ফাংশনের প্রতিটি প্যারামিটারের উপর কিছু কমান্ড চালানো।

    for arg in "$@"; do
        echo "argument: ${arg}"
    done
    
  • কোনো কমান্ডের আউটপুটে হোয়াইটস্পেস দিয়ে আলাদা করা প্রতিটি শব্দের জন্য কিছু কমান্ড চালানো।

    for i in $(seq 10); do
        echo "${i} squared is $((i * i))"
    done
    

    এই স্টাইলের ব্যাপারে কিছু সতর্কতা আমরা পরে দেখব।

অ্যারিথমেটিক for লুপ

Bash-এ সত্যিই একটি অ্যারিথমেটিক লুপ আছে। অন্য প্রোগ্রামিং ভাষার সাথে এটি কিছুটা পরিচিত মনে হবে।

for ((INITIALIZATION; CONDITION; INCREMENT)); do COMMANDS; done

Bash-এ জোড়া প্রথম বন্ধনী একটি অ্যারিথমেটিক কনটেক্সট বোঝায় (Bash অ্যারিথমেটিক নিয়ে আমরা পরের একটি ধারণায় আরও দেখব)। seq ব্যবহার করা উপরের উদাহরণটি এভাবে লেখা যায়

for ((i = 1; i <= 10; i++)); do
    echo "${i} squared is $((i * i))"
done

কখন for ব্যবহার করবেন না

for দিয়ে লাইন পড়বেন না।

এটি একটি অ্যান্টি-প্যাটার্ন, যা আপনি প্রায়ই দেখবেন: cat-এর আউটপুটের উপর ইটারেশন করা।

for line in $(cat some.file); do 
    do_something_with "$line"
done

এটি দুটি কারণে ভুল।

  1. কমান্ড সাবস্টিটিউশনটি কোট ছাড়া লেখা, তাই এটি word splitting-এর অধীন। word splitting ডিফল্টভাবে কেবল নতুন লাইনেই নয়, হোয়াইটস্পেসেও ভাগ করে। এই for লুপ ফাইলের লাইনগুলোর উপর নয়, বরং শব্দগুলোর উপর ইটারেশন করছে।
  2. কমান্ড সাবস্টিটিউশনটি কোট ছাড়া লেখা, তাই এটি filename expansion-এর অধীন। ফাইলের প্রতিটি শব্দ একটি glob প্যাটার্ন হিসেবে মেলানো হবে।

আমরা কোটিং ধারণা-এ শিখেছি, IFS ভ্যারিয়েবল দিয়ে word splitting নিয়ন্ত্রণ করা যায় এবং filename expansion বন্ধ করা যায়। তবে এটি সাধারণত একটি ভঙ্গুর সমাধান। ফাইলের লাইনগুলোর উপর ইটারেশন করার জন্য for ভুল পদ্ধতি। ফাইল পড়ার স্বাভাবিক পদ্ধতি হলো while লুপ।

while লুপ

যতক্ষণ কোনো শর্ত ট্রু থাকে, ততক্ষণ কমান্ডের একটি ক্রম বারবার চালাতে while ব্যবহার করুন।

while CONDITION_COMMANDS; do COMMANDS; done

if-এর মতোই (যেমনটি আমরা কন্ডিশনালস ধারণা-এ শিখেছি, CONDITION_COMMANDS-এর জন্য কোনো বিশেষ সিনট্যাক্স নেই। কমান্ড তালিকার exit status-ই ঠিক করে দেবে "ট্রু" নাকি "ফলস"।

লুপ নিয়ন্ত্রণ

break কমান্ডটি লুপ থেকে বেরিয়ে যায়। এরপর নিয়ন্ত্রণ লুপের শেষে থাকা done-এর পরের কমান্ড থেকে আবার চলতে থাকে।

continue কমান্ডটি লুপের পরের ইটারেশনে চলে যায়।

ফাইলের লাইন পড়া

আগেই বলেছি, ফাইল পড়ার স্বাভাবিক পদ্ধতি হলো while লুপ।

while IFS= read -r line; do
    do_something_with "$line"
done < some.file
  • < রিডাইরেকশন দিয়ে ফাইলের কনটেন্ট লুপের ইনপুট হিসেবে দেওয়া হয়।

  • ইনপুট থেকে একটি সম্পূর্ণ লাইন পড়তে পারলে read কমান্ড "ট্রু" রিটার্ন করে। ইনপুট শেষ হয়ে গেলে, বা শেষ লাইনটির শেষে নতুন লাইন না থাকলে, তখন read "ফলস" রিটার্ন করে।

    • ফাইলের লাইনগুলো পড়ার সত্যিকার অর্থে স্বাভাবিক পদ্ধতি, এমনকি শেষ লাইনটির শেষে নতুন লাইন না থাকলেও, হলো

      while IFS= read -r line || [[ -n "$line" ]]; do ...
      
  • -r অপশনটি read-কে বলে ব্যাকস্ল্যাশ সিকোয়েন্স প্রতিস্থাপন করা যাবে না: ব্যাকস্ল্যাশ শুধুই একটি সাধারণ ক্যারেক্টার।

  • IFS= শুধু read কমান্ডটি চলার সময়ের জন্য IFS-এ খালি স্ট্রিং অ্যাসাইন করে। এতে সাময়িকভাবে word splitting বন্ধ হয়, যাতে ইনকামিং টেক্সট লাইনের শুরু বা শেষে থাকা হোয়াইটস্পেস অক্ষত থাকে।

until

until কনস্ট্রাক্টটি কোনো শর্ত ফলস থাকাকালীন কমান্ডের একটি ক্রম বারবার চালায়। লুপটি শর্ত ট্রু হওয়া পর্যন্ত পুনরাবৃত্তি করে।

until CONDITION_COMMANDS; do COMMANDS; done

until ব্যবহার করা বিরল। সাধারণত "while not" লুপ বেশি ব্যবহার করা হয়।

while ! CONDITION_COMANDS; do ...

অসীম লুপ

কখনও কখনও আপনি চিরকালের জন্য লুপ চালাতে চান। এটা করার দুটি উপায় আছে।

  1. এমন একটি while লুপ, যার শর্তের exit status সবসময় সফল হয়

    while true; do ...
    
  2. খালি এক্সপ্রেশনযুক্ত একটি অ্যারিথমেটিক for লুপ

    for ((;;)); do ...
    

do-while

স্পষ্ট কোনো do-while কনস্ট্রাক্ট নেই, তবে একই ফলাফল আপনি পেতে পারেন:

while true; do
    COMMANDS

    if END_CONDITION; then
        break
    fi
done
GitHub-এর মাধ্যমে সম্পাদনা করুন লিংকটি নতুন একটি উইন্ডো বা ট্যাবে খুলবে