ट्रैक
/
Bash
Bash
/
सिलेबस
/
पाइपलाइन और कमांड सूची
पा

पाइपलाइन और कमांड सूची में Bash

{one: "1 अभ्यास", other: "%{count} अभ्यास"}

पाइपलाइन और कमांड सूची के बारे में

हमने देखा है कि साधारण कमांड कैसे लिखते हैं, जिनमें कमांड के बाद आर्गुमेंट आते हैं। अब हम देखेंगे कि साधारण कमांड को मिलाकर ज़्यादा जटिल कमांड कैसे बनाते हैं।

इनपुट और आउटपुट

शुरू करने से पहले, इनपुट/आउटपुट का एक छोटा परिचय।

प्रक्रियाओं के पास "स्टैंडर्ड I/O चैनल" होते हैं।

  • कोई प्रक्रिया "stdin" से इनपुट ले सकती है।
  • कोई प्रक्रिया "stdout" पर आउटपुट भेज सकती है।
  • कोई प्रक्रिया "stderr" पर एरर आउटपुट भेज सकती है।

tr कमांड इसका बहुत साफ उदाहरण है। यह बस अपने इनपुट से टेक्स्ट पढ़ती है, अक्षरों का ट्रांसलिटरेशन करती है, और तैयार हुए टेक्स्ट को अपने आउटपुट पर छापती है।

"stdio" चैनलों को संभालने के बारे में हम आगे सिलेबस में और देखेंगे।

पाइपलाइन

यह शेल प्रोग्रामिंग के "किलर फीचर" में से एक है। पाइपलाइन की मदद से आप टेक्स्ट की धारा पर जटिल रूपांतरण कर सकते हैं।

उपयोगकर्ताओं की क्रमबद्ध सूची बनाने के लिए:

cat /etc/passwd | cut -d : -f 1 | sort

पाइप का चिह्न (|) एक कमांड के आउटपुट को दूसरी कमांड के इनपुट से जोड़ता है। cut cat के आउटपुट को पढ़ती है, और sort cut के आउटपुट को पढ़ती है।

Advanced
  • डिफॉल्ट रूप से, पाइपलाइन की हर कमांड एक अलग सबशेल में चलती है। (सबशेल एक चाइल्ड प्रोसेस होती है, जो अभी चल रहे शेल की कॉपी होती है।)

  • पाइपलाइन चलाने पर परफॉर्मेंस का खर्च आता है। अगर आपके पास एक जैसी कमांड की लंबी पाइपलाइन बन जाएँ, तो उन्हें एक ही कमांड में मिलाने पर विचार कीजिए। जैसे, जिन पाइपलाइन में 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
  • B चलती है अगर A सफल हो,
  • C चलती है अगर A और B सफल हों,
  • D चलती है अगर A, B और C सफल हों,
  • E चलती है अगर A, B, C या D में से कोई भी फेल हो।
Caution

इन लॉजिकल ऑपरेटरों का इस्तेमाल कम कीजिए। ये जल्दी ही ऐसा कोड बना सकते हैं जिसे पढ़ना मुश्किल हो, या ऐसी लॉजिक जिसे समझना कठिन हो।

जैसे, आप सोच सकते हैं कि ये दोनों एक ही हैं:

if A; then B; else C; fi
A && B || C

फर्क यह है: C कब चलेगी?

  • पहले टुकड़े (यानी if स्टेटमेंट) में C सिर्फ तब चलेगी जब A फेल हो।
  • दूसरे टुकड़े में C तब चलेगी जब A फेल हो या जब A सफल हो लेकिन B फेल हो!

कमांड लिस्ट के उपयोग

यहाँ कुछ उदाहरण हैं जिनमें कमांड लिस्ट कोड को आसान बना सकती है।

फाइल से लाइनों के ब्लॉक पढ़ना

मान लीजिए आपके पास त्रिभुजों का डेटा रखने वाली एक डेटा फाइल है, और हर त्रिभुज को उसकी भुजाओं वाली तीन अलग-अलग लाइनों से दर्शाया गया है।

$ 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")
Note

लाइन कंटीन्यूएशन दो अक्षरों का क्रम है: "बैकस्लैश" और "नई लाइन" (\ + \n)। जब Bash यह क्रम देखता है, तो वह कोड से बस हटा दिया जाता है, और इस तरह मौजूदा लाइन अगली लाइन के साथ जारी रहती है। ध्यान रखिए कि बैकस्लैश और नई लाइन के बीच कोई स्पेस न आने पाए।

यहाँ एक और उदाहरण है

printf "%s\n" "${numbers[@]}" | bc --mathlib | sort --general-numeric-sort

या

printf "%s\n" "${numbers[@]}" \
| bc --mathlib \
| sort --general-numeric-sort
GitHub के ज़रिए संपादित करें यह लिंक नई विंडो या टैब में खुलता है।