আমরা দেখেছি কীভাবে সাধারণ কমান্ড লিখতে হয়, যেখানে একটি কমান্ডের পরে আর্গুমেন্ট থাকে। এখন দেখব কীভাবে সাধারণ কমান্ড জুড়ে দিয়ে আরও জটিল কমান্ড তৈরি করা যায়।
শুরু করার আগে ইনপুট/আউটপুট নিয়ে একটু পরিচিতি জেনে নিই।
প্রসেসগুলোর "স্ট্যান্ডার্ড I/O চ্যানেল" থাকে।
tr কমান্ডটি এর একটি খুব খাঁটি উদাহরণ। এটি কেবল তার ইনপুট থেকে টেক্সট পড়ে, ক্যারেক্টার ট্রান্সলিটারেশন করে, আর ফলাফল টেক্সট তার আউটপুটে প্রিন্ট করে।
"stdio" চ্যানেল নিয়ে কাজ করার বিষয়ে সিলেবাসে পরে আরও দেখব।
এটি শেল প্রোগ্রামিংয়ের অন্যতম প্রধান আকর্ষণ। পাইপলাইন দিয়ে টেক্সটের একটি স্ট্রিমে জটিল রূপান্তর তৈরি করা যায়।
ব্যবহারকারীদের একটি সাজানো তালিকা তৈরি করতে:
cat /etc/passwd | cut -d : -f 1 | sort
পাইপ চিহ্নটি (|) একটি কমান্ডের আউটপুটকে আরেকটি কমান্ডের ইনপুটের সঙ্গে যুক্ত করে। cut পড়ে cat-এর আউটপুট, আর sort পড়ে cut-এর আউটপুট।
ডিফল্টভাবে, পাইপলাইনের প্রতিটি কমান্ড আলাদা একটি সাবশেলে রান করে। (সাবশেল হলো একটি চাইল্ড প্রসেস, যা চলমান শেলের একটি কপি।)
পাইপলাইন রান করার একটি পারফরম্যান্স খরচ আছে।
আপনার যদি একই ধরনের কমান্ডের লম্বা পাইপলাইন জমে যায়, তাহলে সেগুলোকে একটি কমান্ডে মিলিয়ে দেওয়ার কথা ভাবুন।
উদাহরণস্বরূপ, grep, cut, sed, awk আর tr-এর একাধিক ইনস্ট্যান্স ব্যবহার করা পাইপলাইন সাধারণত দক্ষতার জন্য একটি awk কমান্ডে মিলিয়ে ফেলা যায়।
একটি পাইপলাইনের এক্সিট স্ট্যাটাস হলো পাইপলাইনের শেষ কমান্ডের এক্সিট স্ট্যাটাস। এর মানে, আগের কোনো কমান্ড ব্যর্থ হলেও শেষ কমান্ড সফল হলে পুরো পাইপলাইনের এক্সিট স্ট্যাটাস শূন্য হয়।
এটি বদলে দিতে পারে এমন একটি শেল সেটিং আছে;
যদি "pipefail" সেটিং চালু করা থাকে (set -o pipefail দিয়ে), তাহলে পাইপলাইনের এক্সিট স্ট্যাটাস হবে:
কমান্ড লিস্ট হলো ; (বা নিউলাইন), && বা || দিয়ে আলাদা করা পাইপলাইনগুলোর একটি ক্রম।
A; B হলো এমন একটি কমান্ড লিস্ট, যেখানে A শেষ হওয়ার পরে B চলে।A && B, যেখানে B চলে শুধু তখনই, যখন A সফল হয় (শূন্য স্ট্যাটাস নিয়ে এক্সিট করে)।A || B, যেখানে B চলে শুধু তখনই, যখন A ব্যর্থ হয় (অ-শূন্য স্ট্যাটাস নিয়ে এক্সিট করে)।একটি কমান্ড লিস্টের এক্সিট স্ট্যাটাস হলো সর্বশেষ যে কমান্ডটি চালানো হয়েছিল তার এক্সিট স্ট্যাটাস।
&& ও || অপারেটরগুলোকে শিকলে সাজানো যায়, যাতে পরের কমান্ডটি আগের কমান্ডগুলোর স্ট্যাটাসের ভিত্তিতে শর্তসাপেক্ষে চলে। উদাহরণস্বরূপ
A && B && C && D || E
এই লজিক অপারেটরগুলো অল্পই ব্যবহার করুন। এগুলো দ্রুত পড়ার অযোগ্য কোড, বা বোঝা কঠিন এমন লজিক তৈরি করতে পারে।
উদাহরণস্বরূপ, আপনার মনে হতে পারে এগুলো একই:
if A; then B; else C; fi
A && B || C
পার্থক্যটা হলো: C কখন চলে?
if স্টেটমেন্টে), C চলে শুধু A ব্যর্থ হলে।এখানে কয়েকটি উদাহরণ, যেখানে কমান্ড লিস্ট কোডকে সহজ করতে পারে।
ধরুন, আপনার কাছে ত্রিভুজের ডেটা আছে এমন একটি ডেটা ফাইল আছে, আর একটি ত্রিভুজকে প্রকাশ করা হয় তার বাহুগুলো ধারণ করা তিনটি আলাদা লাইন দিয়ে।
$ cat triangle.dat
3
4
5
9
12
14
আপনি একটি while লুপ ব্যবহার করতে পারেন, যেখানে শর্তটি হলো তিনটি আলাদা read কমান্ড:
while read a && read b && read c; do
if is_pythagorean "$a" "$b" "$c"; then
echo "$a:$b:$c is pythagorean"
else
echo "$a:$b:$c is not pythagorean"
fi
done < triangle.dat
ধরে নিলাম is_pythagorean এমন একটি কমান্ড, যা নির্ণয় করে তিনটি বাহু পিথাগোরীয় সমীকরণ মেনে চলে কি না, তাহলে আউটপুট হবে:
3:4:5 is pythagorean
9:12:14 is not pythagorean
অনেক প্রোগ্রামিং ভাষায় এক ধরনের অ্যাসার্শন থাকে, যেখানে কোনো শর্ত ব্যর্থ হলে একটি এক্সেপশন ছোড়া হয়
assert(user == "Administrator", "wrong user");
Bash-এ একটি OR অপারেটর দিয়ে সেই কাজটি করা যায়:
die () { # a little convenience function
echo "$*" >&2
exit 1
}
[[ $user == "Administrator" ]] || die "wrong user"
[[ $password == "secret!" ]] || die "incorrect password"
লম্বা কমান্ড লিস্ট খুব দ্রুতই পড়া কঠিন হয়ে পড়ে। নিউলাইন বেশি করে ব্যবহার করলে অনেক সুবিধা হয়।
এই উদাহরণটি দেখুন, যেখানে দুটি শর্ত পূরণ হলে একটি শব্দ অ্যারেতে যোগ করা হয়।
[[ "$word" != "$topic" ]] && [[ "$key" == "$(sorted "$topic")" ]] && anagrams+=("$candidate")
Bash-এ পাইপ বা লজিক অপারেটরের পরে একটি নিউলাইন যোগ করা যায়।
[[ "$word" != "$topic" ]] &&
[[ "$key" == "$(sorted "$topic")" ]] &&
anagrams+=("$candidate")
তবে লাইনের শেষে অপারেটরটি সহজে চোখ এড়িয়ে যেতে পারে। লাইন কন্টিনিউয়েশন ব্যবহার করলে আপনি অপারেটরটি প্রথমে বসাতে পারেন, যা থেকে স্পষ্ট বোঝা যায় যে লিস্টটি তখনও চলছে:
[[ "$word" != "$topic" ]] \
&& [[ "$key" == "$(sorted "$topic")" ]] \
&& anagrams+=("$candidate")
লাইন কন্টিনিউয়েশন হলো "ব্যাকস্ল্যাশ" আর "নিউলাইন" এই দুই অক্ষরের ক্রম (\ + \n)।
Bash যখন এই ক্রমটি দেখে, তখন এটি কোড থেকে কেবল মুছে যায়, আর এভাবেই পরের লাইন দিয়ে বর্তমান লাইনটি চলতে থাকে।
খেয়াল রাখবেন, ব্যাকস্ল্যাশ আর নিউলাইনের মাঝে যেন কোনো স্পেস না থাকে।
আরেকটি উদাহরণ দেখুন
printf "%s\n" "${numbers[@]}" | bc --mathlib | sort --general-numeric-sort
অথবা
printf "%s\n" "${numbers[@]}" \
| bc --mathlib \
| sort --general-numeric-sort