हमने देखा है कि साधारण कमांड कैसे लिखते हैं, जिनमें कमांड के बाद आर्गुमेंट आते हैं। अब हम देखेंगे कि साधारण कमांड को मिलाकर ज़्यादा जटिल कमांड कैसे बनाते हैं।
शुरू करने से पहले, इनपुट/आउटपुट का एक छोटा परिचय।
प्रक्रियाओं के पास "स्टैंडर्ड 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