Bash-এ লুপ করার দুটি রূপ আছে:
আইটেমের একটি তালিকার উপর ইটারেশন করতে আমরা 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
এই স্টাইলের ব্যাপারে কিছু সতর্কতা আমরা পরে দেখব।
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
এটি একটি অ্যান্টি-প্যাটার্ন, যা আপনি প্রায়ই দেখবেন: cat-এর আউটপুটের উপর ইটারেশন করা।
for line in $(cat some.file); do
do_something_with "$line"
done
এটি দুটি কারণে ভুল।
আমরা কোটিং ধারণা-এ শিখেছি, IFS ভ্যারিয়েবল দিয়ে word splitting নিয়ন্ত্রণ করা যায় এবং filename expansion বন্ধ করা যায়।
তবে এটি সাধারণত একটি ভঙ্গুর সমাধান।
ফাইলের লাইনগুলোর উপর ইটারেশন করার জন্য for ভুল পদ্ধতি।
ফাইল পড়ার স্বাভাবিক পদ্ধতি হলো 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 CONDITION_COMMANDS; do COMMANDS; done
until ব্যবহার করা বিরল।
সাধারণত "while not" লুপ বেশি ব্যবহার করা হয়।
while ! CONDITION_COMANDS; do ...
কখনও কখনও আপনি চিরকালের জন্য লুপ চালাতে চান। এটা করার দুটি উপায় আছে।
এমন একটি while লুপ, যার শর্তের exit status সবসময় সফল হয়
while true; do ...
খালি এক্সপ্রেশনযুক্ত একটি অ্যারিথমেটিক for লুপ
for ((;;)); do ...
স্পষ্ট কোনো do-while কনস্ট্রাক্ট নেই, তবে একই ফলাফল আপনি পেতে পারেন:
while true; do
COMMANDS
if END_CONDITION; then
break
fi
done