ट्रैक
/
Bash
Bash
/
सिलेबस
/
कोटिंग का महत्व
को

कोटिंग का महत्व में Bash

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

कोटिंग का महत्व के बारे में

नए bash प्रोग्रामर को बार-बार यह सलाह सुनने को मिलेगी:

अपने वेरिएबलो को उद्धृत कीजिए!

ऐसा क्यों?

जब आप किसी वेरिएबल (जैसे $name) को एक्सपैंड करते हैं, तो लगभग हमेशा आप चाहते हैं कि उस वेरिएबल की वैल्यू एक ही स्ट्रिंग (या संख्या) की तरह इस्तेमाल हो। आप नहीं चाहते कि वह वैल्यू अनजाने में दो या अधिक अलग-अलग स्ट्रिंग की तरह संभाली जाए।

उद्धरण

किसी टेक्स्ट के टुकड़े को एक ही शब्द की तरह बरतने के लिए उद्धरण ही मुख्य तरीका है। उद्धरण चिह्न मुख्य रूप से दो तरह के होते हैं।

दोहरे उद्धरण चिह्न

दोहरे उद्धरण चिह्नों के अंदर पैरामीटर एक्सपैंशन, अंकगणितीय एक्सपैंशन और कमांड सब्स्टिट्यूशन संभव हैं।

echo "This is bash version $BASH_VERSION"

किसी दोहरे उद्धरण चिह्नों वाली स्ट्रिंग के अंदर एक शाब्दिक डबल कोट डालने के लिए उससे पहले बैकस्लैश लगाइए।

echo "She said \"Let me teach you about bash.\""

एकल उद्धरण चिह्न

एकल उद्धरण चिह्न अपने अंदर किसी भी तरह का एक्सपैंशन नहीं होने देते।

echo 'This is bash version $BASH_VERSION'
# ...^..................................^
# prints exactly: This is bash version $BASH_VERSION

किसी एकल उद्धरण चिह्नों वाली स्ट्रिंग के अंदर एकल उद्धरण चिह्न डालना संभव नहीं है।

उद्धरण का महत्व

echo $name में गड़बड़ी क्या है?

जब शेल कोड की किसी लाइन को पार्स करता है, तो वह एक के बाद एक कई तरह के एक्सपैंशन करता है। इनमें से अंतिम दो एक्सपैंशन वर्ड स्प्लिटिंग और फाइलनेम एक्सपैंशन हैं।

वर्ड स्प्लिटिंग

पैरामीटर एक्सपैंशन, कमांड सब्स्टिट्यूशन या अंकगणितीय एक्सपैंशन का जो भी नतीजा दोहरे उद्धरण चिह्नों के अंदर नहीं बना, वह "वर्ड स्प्लिटिंग" के योग्य है। शेल एक्सपैंड हुए नतीजे को लेता है और उसे $IFS की वैल्यू में मौजूद अक्षरों के किसी भी क्रम पर तोड़ देता है। डिफ़ॉल्ट रूप से यह स्पेस, टैब और न्यूलाइन होता है।

इसे शेल लूप की मदद से काम करते हुए देख सकते हैं:

sentence="The quick brown fox jumps."
i=0
for word in "$sentence"; do echo "$((++i)) $word"; done
# ..........^.........^

आउटपुट:

1 The quick brown fox jumps.

लेकिन बिना उद्धरण के:

i=0
for word in $sentence; do echo "$((++i)) $word"; done
# .........^.........^

आउटपुट:

1 The
2 quick
3 brown
4 fox
5 jumps.

अब इसे $IFS की किसी और वैल्यू के साथ देखिए:

csv="first,second,third"
IFS=","
for word in $csv; do echo "$word"; done

आउटपुट:

first
second
third
वर्ड स्प्लिटिंग बंद करना

वर्ड स्प्लिटिंग बंद करने का एक तरीका यह है कि $IFS को खाली स्ट्रिंग पर सेट कर दिया जाए।

sentence="The quick brown fox jumps."
IFS=    # or explicitly, IFS=""
i=0
for word in $sentence; do echo "$((++i)) $word"; done
# .........^.........^

आउटपुट:

1 The quick brown fox jumps.

लेकिन वेरिएबलो को बिना उद्धरण के छोड़ना तब तक ठीक नहीं माना जाता, जब तक आप फाइलनेम एक्सपैंशन भी बंद न कर दें। ऐसा कैसे करें, यह हम नीचे देखेंगे।

फाइलनेम एक्सपैंशन

"ग्लोब" पैटर्न फाइलों के किसी समूह से मेल खाने वाला छोटा और साफ़ पैटर्न लिखने के लिए इस्तेमाल होते हैं। जैसे, किसी डायरेक्टरी की सारी Markdown फाइलें *.md से मैच की जा सकती हैं। ग्लोब पैटर्न Unix के आविष्कार के समय से ही मौजूद हैं।

ग्लोब के वाइल्डकार्ड अक्षर ये हैं:

  • * किसी भी अक्षर के शून्य या अधिक होने से मेल खाता है,

  • ? किसी भी अक्षर के ठीक एक होने से मेल खाता है,

  • [...] ब्रैकेट के अंदर दिए गए अक्षरों के समूह में से ठीक एक अक्षर से मेल खाता है।

    Advanced
    कैरेक्टर सेट के बारे में बहुत सारी बारीकियाँ हैं। उन्हें देखने के लिए यहाँ क्लिक कीजिए।
    • [abc] ठीक एक ऐसे अक्षर से मेल खाता है जो a या b या c है।
      • किसी एक्सप्रेशन में शाब्दिक क्लोज़ ब्रैकेट शामिल करने के लिए उसे ओपनिंग ब्रैकेट के बाद पहला अक्षर बनाइए (वैकल्पिक ^ के बाद)
        • [][] एक कैरेक्टर सेट है जो क्लोज़ या ओपन ब्रैकेट, दोनों में से किसी एक से मेल खाएगा।
        • या उसे बैकस्लैश से एस्केप कीजिए: [[\]]
    • [x-y] ठीक एक ऐसे अक्षर से मेल खाता है जो x से y तक की रेंज में आता है
      • किसी कैरेक्टर सेट में शाब्दिक हाइफ़न अक्षर शामिल करने के लिए वह ओपनिंग ब्रैकेट के बाद पहला अक्षर होना चाहिए (वैकल्पिक ^ के बाद), या क्लोज़िंग ब्रैकेट से पहले अंतिम अक्षर।
        • [-xy] या [xy-] में से हर एक ठीक एक ऐसे अक्षर से मेल खाता है जो - या x या y है
        • या उसे बैकस्लैश से एस्केप कीजिए: [x\-y]
      • एक से अधिक रेंज दी जा सकती हैं, जैसे [0-9A-Fa-f] किसी हेक्साडेसिमल अंक से मेल खाता है
    • [^abc] ठीक एक ऐसे अक्षर से मेल खाता है जो a या b या c नहीं है,
    • [^x-y] ठीक एक ऐसे अक्षर से मेल खाता है जो x से y तक की रेंज में नहीं आता
    • [[:character_class:]] नामित "character_class" में आने वाले एक अक्षर से मेल खाता है
      • उपलब्ध कैरेक्टर क्लास ये हैं:
        • lower -- छोटे अक्षर
        • upper -- बड़े अक्षर
        • alpha -- अक्षर
        • digit -- अंक
        • alnum -- अक्षर और अंक
        • space -- व्हाइटस्पेस
        • blank -- आड़ा व्हाइटस्पेस (स्पेस और टैब)
        • xdigit -- हेक्साडेसिमल अंक
        • word -- किसी आइडेंटिफ़ायर में इस्तेमाल हो सकने वाले अक्षर (अक्षर, संख्याएँ, अंडरस्कोर)
        • punct -- विराम चिह्न
        • cntrl -- कंट्रोल अक्षर
        • graph -- "दिखने वाले" अक्षर
        • print -- दिखने वाले अक्षर और स्पेस
      • इन्हें आपस में जोड़ा जा सकता है:
        • [[:alpha:]] क्लास [[:lower:][:upper:]] से बनती है
        • [[:alnum:]] क्लास [[:alpha:][:digit:]] से बनती है
        • [[:word:]] क्लास [[:alnum:]_] से बनती है
        • अंडरस्कोर (ऑक्टल 137) [[:word:]] और [[:punct:]] दोनों है
        • [[:graph:]] क्लास [[:alnum:][:punct:]] से बनती है
        • [[:print:]] क्लास [[:graph:] ] से बनती है -- सिर्फ़ स्पेस (ऑक्टल 040), कोई और व्हाइटस्पेस नहीं।
फाइलों की सूची पर इटरेशन

आप for लूप की मदद से फाइलों की सूची पर इटरेशन कर सकते हैं

for file in *.csv; do
    do_something_with "$file"
done

ध्यान दीजिए कि "$file" वेरिएबल उद्धृत है। ग्लोब पैटर्न ऐसी फाइलें भी लौटा सकता है जिनके नाम में स्पेस हो। हमें वेरिएबल को उद्धृत करना होगा ताकि do_something_with कमांड को ठीक एक आर्गुमेंट मिले, वह फाइल का नाम।

ग्लोब पैटर्न रेगुलर एक्सप्रेशन नहीं हैं

ग्लोब पैटर्न रेगुलर एक्सप्रेशन नहीं हैं।

  • ठीक एक अक्षर से मेल खाना
    • रेगेक्स .
    • ग्लोब ?
  • शून्य या अधिक अक्षरों से मेल खाना
    • रेगेक्स .*
    • ग्लोब *
      • ग्लोब पैटर्न .* का मतलब है "ऐसी फाइल के नाम से मेल खाना जिसका पहला अक्षर शाब्दिक डॉट हो और उसके बाद शून्य या अधिक कोई भी अक्षर हों"।
  • एक या अधिक अक्षरों से मेल खाना
    • रेगेक्स .+
    • ग्लोब ?*
  • रेगेक्स के कैरेक्टर सेट और ग्लोब के कैरेक्टर सेट एक ही तरह काम करते हैं।
Advanced

Bash रेगुलर एक्सप्रेशन के और करीब एक्सटेंडेड पैटर्न देता है।

उद्धरण और फाइलनेम एक्सपैंशन

कभी-कभी आप फाइलनेम एक्सपैंशन रोकना चाहते हैं। यूज़र का इनपुट संभालना ऐसा ही एक मौका है। इस कोड स्निपेट को देखिए

read -p "Enter something: " user_input
echo $user_input

अगर यूज़र एक एस्टरिस्क (*) डालता है, तो आउटपुट क्या होगा? मौजूदा डायरेक्टरी की फाइलों की सूची। शायद आप यही नहीं करना चाहते।

एक और उदाहरण है: ऐसे प्रोग्राम को आर्गुमेंट के तौर पर पैटर्न देना जो पैटर्न की उम्मीद करते हैं। tr प्रोग्राम अकसर टेक्स्ट में बदलाव करने के लिए इस्तेमाल होता है। किसी वेरिएबल की वैल्यू को छोटे अक्षरों में बदलने के लिए आप यह कर सकते हैं

var="My Puppet"
echo "$var" | tr '[:upper:]' '[:lower:]'

आउटपुट:

my puppet

एक आम गलती है tr के आर्गुमेंट उद्धृत करना भूल जाना: tr [:upper:] [:lower:]

Caution

यह समस्या क्यों है? बिना उद्धरण वाले ग्लोब पैटर्न मेल खाने वाली फाइलों की सूची में बदल दिए जाएँगे। मान लीजिए आपकी स्क्रिप्ट इस्तेमाल करने वाले व्यक्ति की मौजूदा डायरेक्टरी में p, u और w नाम की फाइलें हैं:

touch p u w
var="My Puppet"
echo "$var" | tr [:upper:] [:lower:]

इससे एक एरर मिलती है!

बिना उद्धरण वाला [:upper:] पैटर्न :, u, p, e या r में से किसी से भी मेल खाता है। बिना उद्धरण वाला [:lower:] पैटर्न :, l, o, w, e या r में से किसी से भी मेल खाता है। Bash पहले पैटर्न के लिए p और u फाइलों से मेल करता है, दूसरे पैटर्न के लिए w फाइल से, और tr को ऐसे कॉल किया जाता है

echo "$var" | tr p u w

और tr के लिए यह आर्गुमेंट की गलत संख्या है।

फाइलनेम एक्सपैंशन बंद करना

फाइलनेम एक्सपैंशन बंद करने के लिए आप set कमांड इस्तेमाल कर सकते हैं।

echo *      # prints a list of files
set -f      # disable filename expansion
echo *      # prints a literal asterisk
set +f      # enable filename expansion
फाइलनेम एक्सपैंशन को नियंत्रित करना

बिल्टिन shopt कमांड की कई सेटिंग्स होती हैं जो तय करती हैं कि फाइलनेम एक्सपैंशन कैसे काम करे। इनमें से दो दिलचस्प सेटिंग्स ये हैं:

  • shopt -s nocaseglob -- केस की परवाह किए बिना मैच करना
  • shopt -s extglob -- एक्सटेंडेड पैटर्न चालू करना
  • shopt -s nullglob -- अगर कोई फाइल मेल न खाए, तो पैटर्न की जगह कुछ न रखें। डिफ़ॉल्ट व्यवहार यह है कि पैटर्न को शाब्दिक स्ट्रिंग की तरह वैसे ही छोड़ दिया जाता है।
GitHub के ज़रिए संपादित करें यह लिंक नई विंडो या टैब में खुलता है।