कोट के बिना रिक्त स्थान के साथ पैरामीटर का विस्तार डबल ब्रैकेट के अंदर क्यों होता है "[[] लेकिन एकल ब्रैकेट के अंदर नहीं" ""?


85

मैं सिंगल या डबल ब्रैकेट का उपयोग करने में भ्रमित हूं। इस कोड को देखें:

dir="/home/mazimi/VirtualBox VMs"

if [[ -d ${dir} ]]; then
    echo "yep"
fi

यह पूरी तरह से काम करता है, हालांकि स्ट्रिंग में एक स्थान होता है। लेकिन जब मैं इसे एकल ब्रैकेट में बदलता हूं:

dir="/home/mazimi/VirtualBox VMs"

if [ -d ${dir} ]; then
    echo "yep"
fi

इसे कहते हैं:

./script.sh: line 5: [: /home/mazimi/VirtualBox: binary operator expected

जब मैं इसे बदलता हूं:

dir="/home/mazimi/VirtualBox VMs"

if [ -d "${dir}" ]; then
    echo "yep"
fi

यह बढ़िया काम करता है। क्या कोई समझा सकता है कि क्या हो रहा है? जब मैं "${var}"रिक्त स्थान के कारण होने वाली समस्याओं को रोकने के लिए चर के आसपास दोहरे उद्धरण निर्दिष्ट करना चाहिए ?



एक और अधिक जेनेरिक बनाम प्रश्न: unix.stackexchange.com/questions/306111/…
Ciro Santilli Sant question question 事件 六四

जवाबों:


83

एकल ब्रैकेट [वास्तव में testकमांड के लिए एक उपनाम है , यह वाक्यविन्यास नहीं है।

एकल ब्रैकेट के डाउनसाइड्स (कई) में से एक यह है कि यदि एक या अधिक ऑपरेंड्स यह खाली स्ट्रिंग वापस करने का मूल्यांकन करने की कोशिश कर रहा है, तो यह शिकायत करेगा कि यह दो ऑपरेंड (बाइनरी) की उम्मीद कर रहा था। यही कारण है कि आप लोगों को ऐसा करते हुए देखते हैं [ x$foo = x$blah ], यह xगारंटी देता है कि ऑपरेंड कभी भी खाली स्ट्रिंग का मूल्यांकन नहीं करेगा।

[[ ]]दूसरी ओर, डबल ब्रैकेट , सिंटैक्स है और इससे कहीं अधिक सक्षम है [ ]। जैसा कि आपको पता चला है, इसमें एक भी ऑपरेंड इश्यू नहीं है और यह >, <, >=, <=, !=, ==, &&, ||ऑपरेटरों के साथ अधिक सी-जैसे सिंटैक्स की भी अनुमति देता है ।

मेरी सिफारिश निम्नलिखित है: यदि आपका दुभाषिया है #!/bin/bash, तो हमेशा उपयोग करें[[ ]]

यह ध्यान रखना महत्वपूर्ण है कि [[ ]]सभी POSIX गोले द्वारा समर्थित नहीं है, हालांकि कई गोले इसका समर्थन करते हैं जैसे कि zshऔर kshइसके अलावाbash


16
खाली स्ट्रिंग (और कई अन्य) समस्या उद्धरणों का उपयोग करके हल की जाती है। जहां: "x" समस्याओं का एक और प्रकार को कवर करना है ऑपरेंड के रूप में लिया जा सकता है ऑपरेटरों । जैसे जब $fooहै !या (या -n... यही समस्या POSIX के गोले के साथ एक समस्या है, जहां तर्क की संख्या (बगल में होना नहीं है [और ]) है चार से अधिक नहीं।
स्टीफन चेज़लस

21
स्पष्ट करने के लिए, [ x$foo = x$blah ]बस के रूप में के रूप में गलत गलत है [ $foo = $bar ][ "$foo" = "$bar" ]किसी भी POSIX आज्ञाकारी खोल में सही है, किसी [ "x$foo" = "x$bar" ]भी बॉर्न जैसे शेल में काम करेगा, लेकिन उन xमामलों के लिए नहीं है जहां आपके पास खाली तार हैं, लेकिन जहां $fooहो सकता है !या -n...
स्टीफन चेज़लस

1
इस उत्तर में दिलचस्प शब्दार्थ। मुझे यकीन नहीं है कि आप इसका क्या मतलब है * नहीं * वाक्यविन्यास । बेशक, के [लिए ठीक से एक उपनाम नहीं है test। यदि ऐसा testहोता , तो एक समापन वर्ग ब्रैकेट को स्वीकार करता। test -n foo ]। लेकिन एक की आवश्यकता testनहीं है [। अन्य सभी मामलों में [समान है test, लेकिन ऐसा नहीं है कि कैसे aliasकाम करता है। बैश का वर्णन करता है [और testके रूप में खोल builtins , लेकिन [[एक के रूप में खोल कीवर्ड
कोजीरो

1
वैसे, बाश में [एक शेल बिल्डिन है, लेकिन / usr / बिन / [एक निष्पादन योग्य भी है। यह पारंपरिक रूप से / usr / bin / test की एक कड़ी है, लेकिन आधुनिक गनु कोरुटिल में एक अलग बाइनरी है। परीक्षण का पारंपरिक संस्करण argv [0] यह देखने के लिए कि क्या इसे [और फिर मेल खाने के लिए खोजा जाता है]।
इवान

मेरा बैश साथ काम नहीं करता है >=और<=
छात्र

51

[आदेश एक साधारण आदेश है। यद्यपि अधिकांश गोले इसे दक्षता के लिए अंतर्निहित के रूप में प्रदान करते हैं, यह शेल के सामान्य वाक्यविन्यास नियमों का पालन करता है। [इसके बिल्कुल बराबर है test, सिवाय इसके कि इसके अंतिम तर्क की [आवश्यकता है ]और testऐसा नहीं है।

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

[[ $x = foo && $y = bar ]]

क्योंकि पूरी सशर्त अभिव्यक्ति शेल द्वारा पार्स की गई है, जबकि [ $x = foo && $y = bar ]पहले दो आदेशों में विभाजित हो जाएगी [ $x = fooऔर ऑपरेटर $y = bar ]द्वारा अलग हो जाएगी &&। इसी तरह डबल ब्रैकेट पैटर्न मिलान वाक्यविन्यास जैसी चीजों को सक्षम करता है, उदाहरण के [[ $x == a* ]]लिए यह परीक्षण करता है कि क्या मूल्य के xसाथ शुरू होता है a; एकल ब्रैकेट में यह उन a*फ़ाइलों की सूची में विस्तारित होगा, जिनके नाम aवर्तमान निर्देशिका में शुरू होते हैं । डबल ब्रैकेट पहले ksh में पेश किए गए थे और केवल ksh, bash और zsh में उपलब्ध हैं।

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

एक अपवाद हालांकि [[ $var1 = "$var2" ]]आप को बाइट-टू-बाइट स्ट्रिंग तुलना करना चाहते हैं, तो आपको उद्धरण चिह्नों की आवश्यकता है, अन्यथा, $var2यह मैच के $var1प्रति एक पैटर्न होगा ।

एक चीज जिसे आप नहीं कर सकते हैं वह [[ … ]]ऑपरेटर के रूप में एक चर का उपयोग करता है। उदाहरण के लिए, यह पूरी तरह से कानूनी है (लेकिन शायद ही कभी उपयोगी):

if [ -n "$reverse_sort" ]; then op=-gt; else op=-lt; fi

if [ "$x" "$op" "$y" ]; then 

अपने उदाहरण में

dir="/home/mazimi/VirtualBox VMs"
if [ -d ${dir} ]; then 

अंदर आदेश ifहै [4 तर्क के साथ -d, /home/mazimi/VirtualBox, VMsऔर ]। शेल पार्स करता है -d /home/mazimi/VirtualBoxऔर फिर पता नहीं क्या करना है VMs। आपको ${dir}एक अच्छी तरह से गठित कमांड प्राप्त करने के लिए शब्द विभाजन को रोकने की आवश्यकता होगी ।

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

  • एक असाइनमेंट में: foo=$bar(लेकिन ध्यान दें कि आपको export "foo=$bar"ऐरो असाइनमेंट में डबल कोट्स की आवश्यकता है जैसे array=("$a" "$b"));
  • एक में caseबयान: case $foo in …;
  • डबल ब्रैकेट के अंदर =या ==ऑपरेटर के दाहिने हाथ को छोड़कर (जब तक आप पैटर्न मिलान नहीं चाहते हैं) [[ $x = "$y" ]]:।

इन सभी में, दोहरे उद्धरण चिह्नों का उपयोग करना सही है, इसलिए आप उन्नत नियमों को छोड़ सकते हैं और हर समय उद्धरणों का उपयोग कर सकते हैं।


1
@StephaneChazelas मेरी एक गलती। यह पता चला है कि [1981 में सिस्टम III से वास्तव में है , मुझे लगा कि यह पुराना था।
गाइल्स

8

जब मैं "${var}"रिक्त स्थान के कारण होने वाली समस्याओं को रोकने के लिए चर के आसपास दोहरे उद्धरण निर्दिष्ट करना चाहिए ?

इस प्रश्न में निहित है

क्यों अच्छा नहीं है?${variable_name}

${variable_name} इसका मतलब यह नहीं है कि आपको क्या लगता है ...

... यदि आप यह है लगता है कि कुछ भी रिक्त स्थान के कारण समस्याओं से कोई लेना देना (चर मान में)। इसके लिए अच्छा है:${variable_name}

$ bar=foo
$ bard=Shakespeare
$ echo $bard
Shakespeare
$ echo ${bar}d
food

और कुछ नहीं! 1  कोई भी अच्छानहीं करता हैजब तक कि आप तुरंत उस चरित्र के साथ अनुसरण नहीं कर रहे हैं जो एक चर नाम का हिस्सा हो सकता है: एक अक्षर (-या-), एक अंडरस्कोर (), या एक अंक (-)। और फिर भी, आप इसके आसपास काम कर सकते हैं:${variable_name}AZaz_09

$ echo "$bar"d
food

मैं इसके उपयोग को हतोत्साहित करने की कोशिश नहीं कर रहा हूँ - echo "${bar}d"शायद यहाँ सबसे अच्छा समाधान है - लेकिन लोगों को उद्धरणों के बजाय ब्रेसिज़ पर निर्भर होने से रोकने के लिए , या सहज रूप से ब्रेसिज़ लगाने और फिर पूछने पर, "अब, मुझे उद्धरणों की भी ज़रूरत है ?" "  आपको हमेशा उद्धरणों का उपयोग करना चाहिए जब तक कि आपके पास एक अच्छा कारण न हो, और आपको यकीन है कि आप जानते हैं कि आप क्या कर रहे हैं।
_________________
1    , ज़ाहिर है, इस तथ्य के लिए कि पैरामीटर विस्तार के कट्टरपंथी रूपों , उदाहरण के लिए, और , सिंटैक्स पर निर्माण करते हैं। इसके अलावा, आप उपयोग करने की आवश्यकता , आदि, 10, 11, आदि, स्थितीय मापदंडों के संदर्भ के लिए - उद्धरण है कि आप के साथ मदद नहीं करेगा।${parameter:-[word]}${parameter%[word]}${parameter}${10}${11}


2

रिक्त स्थान और रिक्त स्थान को संभालने के लिए। चर में विशेष वर्ण आपको हमेशा दोहरे उद्धरण चिह्नों से घेरने चाहिए। एक उचित IFS सेट करना भी एक अच्छा अभ्यास है।

अनुशंसित: http://www.dwheeler.com/essays/filenames-in-shell.html

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.