डबल-कोटिंग कब आवश्यक है?


120

पुरानी सलाह में किसी भी अभिव्यक्ति को दोहरे-उद्धरण के लिए इस्तेमाल किया जाता था $VARIABLE, कम से कम यदि कोई चाहता था कि इसे शेल द्वारा एक एकल आइटम के रूप में व्याख्या की जाए, अन्यथा, सामग्री की कोई भी जगह $VARIABLEशेल से बाहर फेंक देगी।

मैं समझता हूं, हालांकि, गोले के अधिक हाल के संस्करणों में, दोहरे-उद्धरण की आवश्यकता हमेशा नहीं होती है (कम से कम ऊपर वर्णित उद्देश्य के लिए)। उदाहरण के लिए, इसमें bash:

% FOO='bar baz'
% [ $FOO = 'bar baz' ] && echo OK
bash: [: too many arguments
% [[ $FOO = 'bar baz' ]] && echo OK
OK
% touch 'bar baz'
% ls $FOO
ls: cannot access bar: No such file or directory
ls: cannot access baz: No such file or directory

में zsh, दूसरे हाथ पर, एक ही तीन आदेशों सफल होते हैं। इसलिए, इस प्रयोग के आधार पर, ऐसा लगता है कि, bashकोई दोहरे उद्धरणों को अंदर छोड़ सकता है [[ ... ]], लेकिन अंदर नहीं [ ... ]और न ही कमांड-लाइन तर्कों में, जबकि, zshइन सभी मामलों में दोहरे उद्धरणों को छोड़ा जा सकता है।

लेकिन उपर्युक्त जैसे उपाख्यानों से सामान्य नियमों का उल्लेख करना एक प्रस्ताव प्रस्ताव है। जब दोहरे-उद्धरण आवश्यक हैं, तो इसका सारांश देखना अच्छा होगा। मैं मुख्य रूप से में दिलचस्पी रखता हूँ zsh, bashऔर /bin/sh


10
Zsh में आपका मनाया गया व्यवहार सेटिंग्स पर निर्भर करता है और SH_WORD_SPLITविकल्प से प्रभावित होता है।
उलरिच डेंगल


3
एक तरफ के रूप में - ऑल-कैप्स चर नामों का उपयोग चर द्वारा ऑपरेटिंग सिस्टम और शेल के अर्थ के साथ किया जाता है; POSIX विनिर्देश स्पष्ट रूप से अनुप्रयोग परिभाषित चर के लिए निचले मामले के नामों का उपयोग करने की सलाह देता है। (जबकि उद्धृत विनिर्देश पर्यावरण चर पर विशेष रूप से ध्यान केंद्रित कर रहा है, पर्यावरण चर और शेल चर एक नाम स्थान साझा करते हैं: पहले से ही उपयोग किए गए नाम के साथ एक शेल चर बनाने का प्रयास एक पर्यावरण चर बाद वाले को अधिलेखित करता है)। Pubs.opengroup.org/onlinepubs/009695399/basedefs/… , चौथा पैराग्राफ देखें ।
चार्ल्स डफी

जवाबों:


128

सबसे पहले, बाकी हिस्सों से अलग zsh। यह पुराने बनाम आधुनिक गोले की बात नहीं है: zsh अलग तरह से व्यवहार करता है। Zsh डिजाइनरों ने पारंपरिक गोले (बॉर्न, ksh, बैश) के साथ इसे असंगत बनाने का फैसला किया, लेकिन उपयोग करने में आसान है।

दूसरा, जब जरूरत हो तो याद रखना की तुलना में हर समय दोहरे उद्धरण चिह्नों का उपयोग करना कहीं अधिक आसान है। वे समय की सबसे अधिक जरूरत होती है, इसलिए आपको जरूरत पड़ने पर सीखने की जरूरत होगी, न कि जरूरत पड़ने पर।

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

बिना उद्धरण के क्या होता है

ध्यान दें कि दोहरे उद्धरण चिह्नों के बिना, दो चीजें होती हैं।

  1. सबसे पहले, विस्तार का परिणाम (जैसे पैरामीटर प्रतिस्थापन के लिए चर का मूल्य ${foo}, या जैसे कमांड प्रतिस्थापन के लिए कमांड का आउटपुट $(foo)) को शब्दों में विभाजित किया जाता है जहां भी यह व्हाट्सएप होता है।
    अधिक सटीक रूप से, विस्तार का परिणाम प्रत्येक वर्ण पर विभाजित होता है जो IFSचर (विभाजक वर्ण) के मूल्य में प्रकट होता है । यदि विभाजक वर्णों के अनुक्रम में व्हाट्सएप (स्पेस, टैब या न्यूलाइन) होता है, तो व्हॉट्सएप को एकल वर्ण के रूप में गिना जाता है; अग्रणी, अनुगामी या बार-बार गैर-व्हाट्सएप विभाजक खाली क्षेत्रों की ओर ले जाते हैं। उदाहरण के लिए, के साथ IFS=" :", :one::two : three: :four रिक्त फ़ील्ड से पहले पैदा करता है one, के बीच oneऔर twoके बीच, और (एक भी एक) threeऔर four
  2. विभाजन के परिणामस्वरूप होने वाले प्रत्येक क्षेत्र को एक ग्लोब (एक वाइल्डकार्ड पैटर्न) के रूप में व्याख्या की जाती है यदि इसमें वर्णों में से एक होता है \[*?। यदि वह पैटर्न एक या अधिक फ़ाइल नामों से मेल खाता है, तो पैटर्न को मिलान फ़ाइल नामों की सूची से बदल दिया जाता है।

एक निर्विवाद चर विस्तार $fooको बोलचाल की भाषा में "स्प्लिट + ग्लोब ऑपरेटर" के रूप में जाना जाता है, "$foo"जिसके विपरीत बस चर का मान लेता है foo। वही कमांड प्रतिस्थापन के लिए जाता है: "$(foo)"एक कमांड प्रतिस्थापन है, $(foo)एक कमांड प्रतिस्थापन है जिसके बाद विभाजन + ग्लोब होता है।

जहां आप दोहरे उद्धरण चिह्नों को छोड़ सकते हैं

यहां वे सभी मामले हैं जो मैं एक बॉर्न-शैली के खोल के बारे में सोच सकता हूं जहां आप दोहरे उद्धरण के बिना एक चर या कमांड प्रतिस्थापन लिख सकते हैं, और मूल्य की शाब्दिक व्याख्या की जाती है।

  • एक असाइनमेंट के दाईं ओर।

    var=$stuff
    a_single_star=*

    ध्यान दें कि आपको दोहरे उद्धरण चिह्नों की आवश्यकता है export, क्योंकि यह एक सामान्य बिलिन है, न कि कोई कीवर्ड। यह केवल कुछ गोले जैसे कि डैश, zsh (sh emulation में), यश या पॉश में सही है; bash और ksh दोनों exportविशेष रूप से व्यवहार करते हैं ।

    export VAR="$stuff"
  • एक caseबयान में

    case $var in 

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

    a_star='a*'
    case $var in
      "$a_star") echo "'$var' is the two characters a, *";;
       $a_star) echo "'$var' begins with a";;
    esac
  • डबल कोष्ठक के भीतर। डबल ब्रैकेट शेल विशेष सिंटैक्स हैं।

    [[ -e $filename ]]

    के दाहिने हाथ की ओर: सिवाय इसके कि आप दोहरे उद्धरण चिह्नों जहां एक पैटर्न या रेगुलर एक्सप्रेशन की उम्मीद है की जरूरत है =या ==या !=या =~

    a_star='a*'
    if [[ $var == "$a_star" ]]; then echo "'$var' is the two characters a, *"
    elif [[ $var == $a_star ]]; then echo "'$var' begins with a"
    fi

    आपको एकल कोष्ठक के भीतर हमेशा की तरह दोहरे उद्धरण चिह्नों की आवश्यकता होती है [ … ]क्योंकि वे साधारण शेल सिंटैक्स होते हैं (यह एक कमांड है जिसे कहा जाता है [)। सिंगल या डबल ब्रैकेट देखें

  • गैर-इंटरैक्टिव POSIX गोले में एक पुनर्निर्देशन में (न bash, न ही ksh88)।

    echo "hello world" >$filename

    कुछ गोले, जब संवादात्मक होते हैं, तो चर के मूल्य को वाइल्डकार्ड पैटर्न के रूप में मानते हैं। POSIX गैर-संवादात्मक गोले में उस व्यवहार को प्रतिबंधित करता है, लेकिन कुछ गोले जिसमें पोश (POSIX मोड को छोड़कर) और ksh88 को शामिल किया गया है (जब यह पाया जाता है, तो (माना जाता है) sh, जैसे कि Solaris जैसे कुछ व्यावसायिक यूनियनों का POSIX अभी भी वहां मौजूद है ( विभाजन काbash प्रयास भी करता है ) और पुनर्निर्देशन में विफल रहता है जब तक कि विभाजन ग्लोबिंग + वास्तव में एक शब्द में परिणाम) है, जिसके कारण यह बेहतर है एक में पुनर्निर्देशन के लक्ष्य को उद्धृत करने के मामले में स्क्रिप्ट आप एक करने के लिए इसे परिवर्तित करना चाहते हैं स्क्रिप्ट कुछ दिन, या इसे चलाने के लिए एक प्रणाली पर जहां है उस बिंदु पर गैर-अनुपालन, या यह इंटरैक्टिव गोले से खट्टा हो सकता है ।shbashsh

  • एक अंकगणितीय अभिव्यक्ति के अंदर। वास्तव में, आपको अंकगणित को एक अंकगणितीय अभिव्यक्ति के रूप में पार्स करने के लिए छोड़ने की आवश्यकता है।

    expr=2*2
    echo "$(($expr))"

    हालाँकि, आपको अंकगणित विस्तार के आसपास उद्धरणों की आवश्यकता है क्योंकि वे अधिकांश गोले में शब्द विभाजन के अधीन हैं क्योंकि PIXIX ((!) की आवश्यकता होती है।

  • एक सहयोगी सरणी सबस्क्रिप्ट में।

    typeset -A a
    i='foo bar*qux'
    a[foo\ bar\*qux]=hello
    echo "${a[$i]}"

निर्विवाद चर और कमांड प्रतिस्थापन कुछ दुर्लभ परिस्थितियों में उपयोगी हो सकता है:

  • जब परिवर्तनीय मूल्य या कमांड आउटपुट में ग्लोब पैटर्न की एक सूची होती है और आप इन पैटर्नों का मिलान फाइलों की सूची में करना चाहते हैं।
  • जब आप जानते हैं कि मूल्य में कोई वाइल्डकार्ड वर्ण नहीं है, तो $IFSइसे संशोधित नहीं किया गया था और आप इसे व्हाट्सएप वर्णों में विभाजित करना चाहते हैं।
  • जब आप किसी निश्चित वर्ण पर एक मान विभाजित करना चाहते हैं: ग्लोबिंग को अक्षम करें set -f, IFSविभाजक वर्ण पर सेट करें (या इसे व्हाट्सएप पर विभाजित करने के लिए अकेला छोड़ दें), फिर विस्तार करें।

Zsh

Zsh में, आप कुछ अपवादों के साथ, अधिकांश समय दोहरे उद्धरण छोड़ सकते हैं।

  • $varकभी भी कई शब्दों का विस्तार नहीं होता है, हालाँकि यह खाली सूची (एकल, खाली शब्द से युक्त सूची के विपरीत) के लिए फैलता है यदि varरिक्त स्ट्रिंग का मान है। कंट्रास्ट:

    var=
    print -l $var foo        # prints just foo
    print -l "$var" foo      # prints an empty line, then foo

    इसी प्रकार, "${array[@]}"सरणी के सभी तत्वों तक $arrayफैल जाता है , जबकि केवल गैर-खाली तत्वों तक फैलता है।

  • @पैरामीटर विस्तार ध्वज कभी कभी पूरी प्रतिस्थापन को दोहरे उद्धरण चिह्नों की आवश्यकता है: "${(@)foo}"

  • कमांड प्रतिस्थापन क्षेत्र को विभाजित करता है यदि अयोग्य है: echo $(echo 'a'; echo '*')प्रिंट a *(एक ही स्थान के साथ) जबकि echo "$(echo 'a'; echo '*')"अनमॉडिफाइड दो-लाइन स्ट्रिंग प्रिंट करता है। "$(somecommand)"एक शब्द, अंतिम अंतिम समाचारों में कमांड का आउटपुट प्राप्त करने के लिए उपयोग करें । "${$(somecommand; echo _)%?}"अंतिम newlines सहित कमांड का सटीक आउटपुट प्राप्त करने के लिए उपयोग करें । "${(@f)$(somecommand)}"कमांड के आउटपुट से सरणी की एक पंक्ति प्राप्त करने के लिए उपयोग करें ।


वास्तव में, आपको अंकगणित को एक अंकगणितीय अभिव्यक्ति के रूप में पार्स करने के लिए छोड़ने की आवश्यकता है। मैं आपके उदाहरण को उद्धरण के साथ काम करने में सक्षम क्यों हूं:echo "$(("$expr"))"
साइकर

यह वही है जो man bashकहता है: अभिव्यक्ति को ऐसे माना जाता है जैसे कि यह दोहरे उद्धरण चिह्नों के भीतर है, लेकिन कोष्ठकों के अंदर एक दोहरे उद्धरण का विशेष रूप से व्यवहार नहीं किया जाता है।
सायकर

4
इसके अलावा, जो कोई दिलचस्पी है, की औपचारिक नाम विभाजन + ग्लोब हैं शब्द बंटवारे और पथ नाम विस्तार
सायकर

3
FYI करें - StackOverflow पर , मैंने किसी को "वैकल्पिक जब एक कच्ची स्ट्रिंग की उम्मीद है" खींच दिया है तो इस उत्तर में भाषा एक तर्क का हवाला देते हुए बचाव नहीं करती है echo। यह भाषा को और भी अधिक स्पष्ट करने की कोशिश करने के लायक हो सकता है ("जब पार्सर द्वारा एक कच्ची स्ट्रिंग की उम्मीद की जाती है", तो शायद?)
चार्ल्स डफी

2
@CharlesDuffy उघ, मैंने इस गलतफहमी के बारे में नहीं सोचा था। मैंने "कब" को "कब" में बदल दिया है और आपके द्वारा सुझाए अनुसार वाक्य को मजबूत किया है।
गाइल्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.