क्यों एक शेल कीवर्ड बनाया गया है?


64

जहाँ तक मुझे पता है, [[का एक बढ़ाया संस्करण है [, लेकिन जब मैं [[एक कीवर्ड के रूप में देखता हूं और [एक बिल्डिन के रूप में दिखाया जा रहा हूं तो मैं उलझन में हूं ।

[root@server ~]# type [
[ is a shell builtin
[root@server ~]# type [[
[[ is a shell keyword

टीएलडीपी का कहना है

एक बिलिन उसी नाम के सिस्टम कमांड का एक पर्याय हो सकता है, लेकिन बैश आंतरिक रूप से इसे पुन: लागू करता है। उदाहरण के लिए, बैश इको कमांड / बिन / गूंज के समान नहीं है, हालांकि उनका व्यवहार लगभग समान है।

तथा

एक कीवर्ड एक आरक्षित शब्द है, टोकन या ऑपरेटर। कीवर्ड का शेल के लिए एक विशेष अर्थ है, और वास्तव में शेल के सिंटैक्स के बिल्डिंग ब्लॉक हैं। उदाहरण के लिए, के लिए, जबकि, करते हैं, और! कीवर्ड हैं। बिलिन के समान, एक कीवर्ड बैश में हार्ड-कोडित है, लेकिन एक बिलिन के विपरीत, एक कीवर्ड अपने आप में एक कमांड नहीं है, लेकिन एक कमांड निर्माण का एक सबयूनिट है। [2]

क्या यह दोनों [और [[एक खोजशब्द नहीं बनाना चाहिए ? क्या ऐसा कुछ है जो मुझे यहां याद आ रहा है? इसके अलावा, इस लिंक फिर से पुष्टि है कि दोनों [और [[एक ही तरह से संबंधित होना चाहिए।



9
/ बिन / [मेरी मशीन पर मौजूद है।
यहोशू

2
दोनों के बीच एक अंतर के एक साधारण प्रदर्शन के if "[" $x -eq 3 ]रूप में : अपेक्षित के रूप में काम करता है (क्योंकि बैश नामक कमांड के लिए दिखता है [, और यह मौजूद है), लेकिन if "[[" $x -eq 3 ]]काम नहीं करता है (क्योंकि एक बार फिर बैश उपयुक्त नाम की कमान खोजता है, लेकिन कोई भी नहीं है [[आदेश)।
काइल स्ट्रैंड

1
@ जोशुआ तो करता है /usr/bin/echo, लेकिन इसका मतलब यह नहीं है कि यह एक बिलिन नहीं है ।
जोनाथन रेनहार्ट

सभी bulitins जो बाह्य रूप से पार्स तर्कों में मौजूद हैं यदि वे निर्मित नहीं थे।
यहोशू

जवाबों:


80

के बीच अंतर [और [[काफी मौलिक है।

  • [एक आदेश है। इसके तर्कों को वैसे ही संसाधित किया जाता है जैसे किसी अन्य आदेश तर्क को संसाधित किया जाता है। उदाहरण के लिए, विचार करें:

    [ -z $name ]

    शेल परिणाम का विभाजन और फ़ाइल नाम दोनों का विस्तार $nameऔर प्रदर्शन करेगा , जैसे कि यह किसी अन्य कमांड के लिए होगा।

    एक उदाहरण के रूप में, निम्नलिखित विफल हो जाएगा:

    $ name="here and there"
    $ [ -n $name ] && echo not empty
    bash: [: too many arguments

    इस काम को सही ढंग से करने के लिए, उद्धरण आवश्यक हैं:

    $ [ -n "$name" ] && echo not empty
    not empty
  • [[एक शेल कीवर्ड है और इसके तर्कों को विशेष नियमों के अनुसार संसाधित किया जाता है। उदाहरण के लिए, विचार करें:

    [[ -z $name ]]

    शेल का विस्तार होगा $name, लेकिन किसी भी अन्य कमांड के विपरीत, यह परिणाम पर न तो शब्द विभाजन और ही फाइलनाम का प्रदर्शन करेगा । उदाहरण के लिए, निम्नलिखित रिक्त स्थान के बावजूद सफल होगा name:

    $ name="here and there"
    $ [[ -n $name ]] && echo not empty
    not empty

सारांश

[ एक कमांड है और अन्य सभी कमांड के समान नियमों के अधीन है जो शेल निष्पादित करता है।

क्योंकि [[एक कीवर्ड है, एक कमांड नहीं है, हालांकि, शेल इसे विशेष रूप से मानता है और यह बहुत अलग नियमों के तहत संचालित होता है।


+1। धन्यवाद। क्या आप एक कमांड और एक कीवर्ड संचालित करने वाले नियमों के तहत स्रोत (संदर्भ) दे सकते हैं?
टिम

नियम है जिसके तहत @Tim आदेश संचालित में विस्तृत कर रहे हैं man bash। विशेष रूप से, "SIMPLE COMMAND EXPANSION" और "COMMAND EXECUTION" शीर्षक वाले अनुभाग देखें। के अलावा [[, अन्य पार्टी कीवर्ड शामिल if, then, while, और 'मामले'। कीवर्ड के लिए कोई सामान्य नियम नहीं हैं: प्रत्येक कीवर्ड एक विशेष मामला है। man bash प्रत्येक के लिए विवरण शामिल हैं।
8:10 बजे जॉन 1024

62

में V7 यूनिक्स जहां बॉर्न शैल अपनी शुरुआत की - - [बुलाया गया था test, और यह केवल के रूप में अस्तित्व /bin/test। इसलिए, आप आज जैसा कोड लिखेंगे:

if [ "$foo" = "bar" ] ; then ...

आप के बजाय लिखा होगा

if test "$foo" = "bar" ; then ...

यह दूसरा अंकन अभी भी मौजूद है, और मुझे पता है कि यह क्या चल रहा है इसके बारे में अधिक स्पष्ट है: आप एक कमांड को बुला रहे हैं test, जो इसके तर्कों का मूल्यांकन करता है और एक निकास स्थिति कोड देता है जो यह ifतय करने के लिए उपयोग करता है कि आगे क्या करना है। वह कमांड शेल में बनाया जा सकता है, या यह एक बाहरी प्रोग्राम हो सकता है। into

[बाद में testआने के लिए एक विकल्प के रूप में। यह एक अंतर्निहित पर्यायवाची हो सकता है test, लेकिन यह /bin/[आधुनिक प्रणालियों पर भी दिया जाता है जो गोले के रूप में नहीं होता है।

[और testउसी कोड का उपयोग करके लागू किया जा सकता है। यह बात लागू होती है /bin/[और /bin/testओएस एक्स, जहां इन कर रहे हैं पर हार्ड लिंक एक ही executable.³ नतीजतन करने के लिए, कार्यान्वयन पूरी तरह से अनुगामी पर ध्यान नहीं देता ]: यह यह की आवश्यकता नहीं है, तो आप के रूप में इसे कहते /bin/[हैं, और यह शिकायत नहीं कर रहा है यदि आप इसे प्रदान करते हैं /bin/test.⁴

उस इतिहास में से कोई भी प्रभावित नहीं करता है [[, क्योंकि वहां कभी भी एक मौलिक कार्यक्रम नहीं था [[। यह उन गोले के अंदर पूरी तरह से मौजूद है जो इसे POSIX खोल के विस्तार के रूप में लागू करते हैं ।

"बिल्टिन" और "कीवर्ड" के बीच अंतर का एक हिस्सा इस इतिहास के कारण है। यह भी सच है कि पार्सिंग के लिए सिंटैक्स नियमों को दर्शाता है [[भाव अलग, के रूप में में बताया है John1024 के जवाब .⁵


फुटनोट:

  1. जब आप इसे इस तरह से देखते हैं, तो यह स्पष्ट करता है कि आपको [अधिकांश अन्य प्रोग्रामिंग भाषाओं में जिस तरह से कोष्ठक और कोष्ठक काम करते हैं, उसके विपरीत आपको शेल स्क्रिप्ट में स्थान क्यों रखना चाहिए । यदि शेल के कमांड पार्सर ने अनुमति दी है if["$x"..., तो उसे भी अनुमति देनी होगीiftest"$x"...

  2. यह 1980 के आसपास हुआ। 1979 से प्राचीन यूनिक्स V7/bin/[ की मेरी प्रति मौजूद नहीं है , न ही इसे एक उपनाम के रूप में प्रलेखित किया गया है। मैं का एक पूर्व रिहाई के पिछले भाग में है इसी आदमी पेज प्रविष्टि में प्रणाली III 1980 से मैनुअल, यह है सूचीबद्ध।man test

  3. ls -i /bin/[ /bin/test

  4. लेकिन इस व्यवहार पर भरोसा मत करो। बैश बिल्ट-इन के संस्करण [को बंद करने की आवश्यकता होती है ], और testयदि आप इसे प्रदान करते हैं तो इसका अंतर्निहित कार्यान्वयन शिकायत करेगा ।

  5. बिलियन बनाम एक्सटर्नल कमांड भेद भी एक अन्य कारण से हो सकता है: दो कार्यान्वयन अलग-अलग व्यवहार कर सकते हैं। echoकई प्रणालियों पर यह मामला है। क्योंकि केवल एक कार्यान्वयन है, किसी कीवर्ड के लिए ऐसा कोई भेद करने की आवश्यकता नहीं है।


आप युवा @Warren धन्यवाद, लेकिन क्यों builtinऔर keywordके बीच भेद [और [[जब दोनों एक ही कार्यक्षमता (तथ्य यह है कि सिवाय प्रदान करता है [[की तुलना में अधिक सुविधाओं के साथ आता [)?
श्री

2
@sree [[एक कीवर्ड होने के कारण उन चीजों को करने की अनुमति देता है जो संभव नहीं हैं [- उदाहरण के लिए उद्धृत करना बहुत समय आवश्यक नहीं है, क्योंकि शेल को पता है कि यह एक चर है। कहने का तात्पर्य यह है कि किसी कीवर्ड का उपयोग करने पर कमांड लाइन की प्रोसेसिंग प्रभावित होती है, लेकिन तब नहीं जब एक बिलिन का उपयोग किया जाता है - जो कि बहुत बाद में होता है।
मूरू

1
ध्यान दें कि V7 बॉर्न शेल के लिए कोड एक [बिलिन दिखाता है , लेकिन कोड टिप्पणी करता है।
स्टीफन चेजलस

cdएक बिलिन है, लेकिन यह कुछ भी छाया नहीं करता है ( cdबाहरी कार्यक्रम के रूप में लागू नहीं किया जा सकता है)।
पाओलो एबरमन

2
यह एक उत्कृष्ट ऐतिहासिक सारांश है, लेकिन यह (IMO) महत्वपूर्ण विवरण को छोड़ देता है, जो कि मोरू द्वारा और उनके उत्तर में जॉन 1024 द्वारा इंगित किया गया है, कि [[एक कीवर्ड बनाने से शेल अपने तर्कों के लिए विशेष पार्सिंग नियमों का उपयोग करने की अनुमति देता है। इस प्रकार, अफसोस, मेरे upvote John1024 को जाता है।
इल्मरी करोनें

3

[मूल रूप से सिर्फ एक बाहरी आदेश था, जिसका दूसरा नाम था /bin/test। लेकिन कुछ आदेश, जैसे कि [और echo, शेल स्क्रिप्ट में इतनी बार उपयोग किए जाते हैं कि शेल कार्यान्वयनकर्ताओं ने कोड को सीधे शेल में ही कॉपी करने का निर्णय लिया, बजाय इसके कि वे उपयोग किए जाने वाले हर बार एक और प्रक्रिया को चलाएं। उसने इन आदेशों को "बिल्डिंस" में बदल दिया, हालांकि आप अभी भी बाहरी कार्यक्रम को इसके पूर्ण पथ के माध्यम से आमंत्रित कर सकते हैं।

[[बहुत बाद में आया। हालांकि अंतर्निहित शेल के भीतर आंतरिक रूप से कार्यान्वित किया जाता है, इसे बाहरी आदेशों की तरह ही पार्स किया जाता है। जैसा कि जॉन 1024 के उत्तर में बताया गया है, इसका मतलब है कि अनक्वालेटेड वेरिएबल्स पर शब्द विभाजन हो जाएगा, और टोकन जैसे >और <I / O पुनर्निर्देशन के रूप में संसाधित होते हैं। इसने लेखन की तुलनात्मक अभिव्यक्तियों को असुविधाजनक बना दिया। [[शेल सिंटैक्स के रूप में बनाया गया था, ताकि इसे वैचारिक रूप से पार्स किया जा सके। [[चर के भीतर शब्द विभाजन नहीं मिलता है, <और >तुलना ऑपरेटरों के रूप में इस्तेमाल किया जा सकता है, =इस पर निर्भर करता है कि अगला पैरामीटर उद्धृत किया गया है या नहीं, आदि के आधार पर अलग-अलग व्यवहार कर सकते हैं। ये सभी उपयुक्तताएं हैं जो [[पारंपरिक [कमांड / बिल्डिन की तुलना में उपयोग करना आसान बनाते हैं ।

वे बस [इस तरह से वाक्यविन्यास के रूप में पुनरावृत्ति नहीं कर सकते थे क्योंकि यह लाखों लिपियों के लिए एक असंगत परिवर्तन होता। नए [[सिंटैक्स का उपयोग करके , जो पहले से मौजूद नहीं था, वे पूरी तरह से उसी तरीके से सुधार कर सकते हैं जो एक ऊपर की ओर संगत तरीके से उपयोग किया जाता है।

यह उस विकास के समान है जिसके परिणामस्वरूप $((...))अंकगणितीय अभिव्यक्तियों के लिए वाक्यविन्यास हुआ , जिसने ज्यादातर पारंपरिक exprकमांड को बदल दिया है ।


0

नए [[में bashएक है अनुकूलन की [

क्लासिक [में एक बड़ी खामी है, जब इसे एक तुच्छ ऑपरेशन करने के लिए अक्सर उपयोग किया जाता है: यह हर बार एक नई प्रक्रिया को जन्म देगा:
(यह तुलना करने के लिए एक नया पता स्थान बनाता है 0और 1! हर बार!)

मुझे लगता है कि जोड़ने का एक मुख्य बिंदु एक अतिरिक्त प्रक्रिया नहीं होने के [[अंदर अभिव्यक्ति का मूल्यांकन करना था [। लेकिन [काम कैसे किया जा सकता है इसे बदला नहीं जा सकता है - यह बहुत भ्रम और समस्याएं पैदा करेगा। इसलिए, अनुकूलन को एक नए नाम के साथ लागू किया गया था, और अधिक कुशल तरीके से, अर्थात् शेल बिलिन कमांड।
यह एक साइड इफेक्ट के रूप में शेल सिंटैक्स में कीवर्ड बन गया।

पहले समय [का उपयोग किया जाता था, यह बाहरी प्रक्रिया के साथ करने का सही तरीका था


5
ध्यान दें कि हालांकि [मूल रूप से एक बाहरी कमांड था, इसे बिल्ट-इन शेल के रूप में काफी पहले जोड़ा गया था, शायद तब तक यूनिक्स सिस्टम III जारी किया गया था और निश्चित रूप से यूनिक्स सिस्टम वी जारी होने से पहले। इसलिए, 'अतिरिक्त प्रक्रिया' उम्र के लिए कोई समस्या नहीं है। हालांकि, वाक्यविन्यास अपरिवर्तित रहा - यह माना जाता था कि यह एक बाहरी आदेश होगा।
जोनाथन लेफ़लर

@JonathanLeffler ओह, धन्यवाद, मैं चूक गया कि [दोनों है - इसका मतलब है कि कुछ बदलाव ...
Volker Siegel
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.