शेल बिलिन और शेल कीवर्ड के बीच अंतर क्या है?


33

जब मैं इन दोनों आदेशों को चलाता हूं, मुझे मिलता है

$ type cd
cd is a shell builtin
$ type if
if is a shell keyword

यह स्पष्ट रूप से दिखाया गया है कि cdशेल शेल है और ifशेल कीवर्ड है। तो शेल बिल्ड और कीवर्ड के बीच अंतर क्या है?


जवाबों:


45

बैश और कीवर्ड के बीच एक मजबूत अंतर है, जिस तरह से बैश आपके कोड को पार्स करता है। इससे पहले कि हम अंतर के बारे में बात करें, आइए सभी खोजशब्दों और बिल्डरों को सूचीबद्ध करें:

Builtins:

$ compgen -b
.         :         [         alias     bg        bind      break     
builtin   caller    cd        command   compgen   complete  compopt   
continue  declare   dirs      disown    echo      enable    eval      
exec      exit      export    false     fc        fg        getopts   
hash      help      history   jobs      kill      let       local     
logout    mapfile   popd      printf    pushd     pwd       read      
readarray readonly  return    set       shift     shopt     source    
suspend   test      times     trap      true      type      typeset   
ulimit    umask     unalias   unset     wait                          

कीवर्ड:

$ compgen -k
if        then      else      elif      fi        case      
esac      for       select    while     until     do        
done      in        function  time      {         }         
!         [[        ]]        coproc              

ध्यान दें कि, उदाहरण के [लिए एक बिलिन है और [[यह एक कीवर्ड है। मैं इन दोनों का उपयोग नीचे के अंतर को स्पष्ट करने के लिए करूँगा, क्योंकि वे जाने-माने संचालक हैं: हर कोई उन्हें जानता है और नियमित रूप से उनका उपयोग करता है (या चाहिए)।

किसी कीवर्ड को बैश द्वारा उसके पार्सिंग में बहुत पहले ही स्कैन और समझा जाता है। यह उदाहरण के लिए निम्नलिखित की अनुमति देता है:

string_with_spaces='some spaces here'
if [[ -n $string_with_spaces ]]; then
    echo "The string is non-empty"
fi

यह ठीक काम करता है, और बैश खुशी से उत्पादन करेगा

The string is non-empty

ध्यान दें कि मैंने उद्धरण नहीं दिया $string_with_spaces। जबकि निम्नलिखित:

string_with_spaces='some spaces here'
if [ -n $string_with_spaces ]; then
    echo "The string is non-empty"
fi

दिखाता है कि बैश खुश नहीं है:

bash: [: too many arguments

यह कीवर्ड के साथ काम क्यों करता है और बिलिन के साथ नहीं? क्योंकि जब बैश कोड को पार्स करता है, तो यह देखता है कि [[कौन सा कीवर्ड है, और बहुत जल्दी समझता है कि यह विशेष है। तो यह समापन की तलाश ]]करेगा और एक विशेष तरीके से अंदर का इलाज करेगा। एक बिलिन (या कमांड) को वास्तविक कमांड के रूप में माना जाता है जिसे तर्कों के साथ कहा जाने वाला है। इस अंतिम उदाहरण में, बैश समझता है कि उसे [तर्कों के साथ कमांड चलाना चाहिए (प्रति पंक्ति एक दिखाया गया है):

-n
some
spaces
here
]

परिवर्तनशील विस्तार, उद्धरण हटाने, पथनाम विस्तार और शब्द विभाजन के बाद से होता है। कमांड [शेल में बनाया जाता है, इसलिए यह इन तर्कों के साथ निष्पादित करता है, जिसके परिणामस्वरूप त्रुटि होती है, इसलिए शिकायत।

व्यवहार में, आप देखते हैं कि यह अंतर परिष्कृत व्यवहार के लिए अनुमति देता है, जो कि बिल्डिंस (या कमांड) के साथ संभव नहीं होगा।

फिर भी व्यवहार में, आप संभवतः एक कीवर्ड से एक बिलियन को कैसे अलग कर सकते हैं? यह प्रदर्शन करने के लिए एक मजेदार प्रयोग है:

$ a='['
$ $a -d . ]
$ echo $?
0

जब बैश लाइन को पार्स करता है $a -d . ], तो यह कुछ भी विशेष नहीं देखता है (यानी, कोई उपनाम नहीं, कोई पुनर्निर्देशन नहीं, कोई कीवर्ड नहीं), इसलिए यह केवल चर विस्तार करता है। चर विस्तार के बाद, यह देखता है:

[ -d . ]

इसलिए [तर्कों के साथ कमांड (बिलिन) निष्पादित करता है -d, .और ], जो निश्चित रूप से सच है (यह केवल परीक्षण करता .है कि क्या एक निर्देशिका है)।

अब देखो:

$ a='[['
$ $a -d . ]]
bash: [[: command not found

ओह। ऐसा इसलिए है क्योंकि जब बैश इस लाइन को देखता है, तो यह कुछ खास नहीं देखता है, और इसलिए सभी चर का विस्तार करता है, और अंततः देखता है:

[[ -d . ]]

इस समय, उर्फ ​​विस्तार और कीवर्ड स्कैनिंग लंबे समय से किया गया है और अब प्रदर्शन नहीं किया जा रहा है, इसलिए बैश कमांड को खोजने की कोशिश करता है [[, इसे नहीं ढूंढता है, और शिकायत करता है।

समान पंक्तियों के साथ:

$ '[' -d . ]
$ echo $?
0
$ '[[' -d . ]]
bash: [[: command not found

तथा

$ \[ -d . ]
$ echo $?
0
$ \[[ -d . ]]
bash: [[: command not found

उपनाम विस्तार कुछ खास नहीं है। आप सभी ने निम्नलिखित को कम से कम एक बार किया है:

$ alias ll='ls -l'
$ ll
.... <list of files in long format> ....
$ \ll
bash: ll: command not found
$ 'll'
bash: ll: command not found

तर्क समान होता है: उपनाम विस्तार चर विस्तार और उद्धरण हटाने से बहुत पहले होता है।


कीवर्ड बनाम उपनाम

अब आपको क्या लगता है कि क्या हम एक उपनाम को एक खोजशब्द के रूप में परिभाषित करते हैं?

$ alias mytest='[['
$ mytest -d . ]]
$ echo $?
0

ओह, यह काम करता है! इसलिए उपनामों का उपयोग उपनामों के लिए किया जा सकता है! जानकर अच्छा लगा।


निष्कर्ष: बिलिंस वास्तव में आदेशों की तरह व्यवहार करते हैं: वे उन क्रियाओं के अनुरूप होते हैं जो प्रत्यक्ष चर विस्तार और शब्द विभाजन और ग्लोबिंग से गुजरती हैं। यह वास्तव में सिर्फ एक बाहरी आदेश होने जैसा है /binया /usr/binजिसमें परिवर्तनशील विस्तार के बाद दिए गए तर्कों के साथ कहा जाता है, आदि। ध्यान दें कि जब मैं कहता हूं कि यह वास्तव में एक बाहरी आदेश होने के समान है, तो मेरा मतलब केवल तर्कों, शब्द विभाजन, ग्लोबिंग, आदि के संबंध में है। चर विस्तार, आदि। एक अंतर्निहित शेल की आंतरिक स्थिति को संशोधित कर सकता है!

दूसरी ओर, कीवर्ड स्कैन किए जाते हैं और बहुत जल्दी समझ में आते हैं, और परिष्कृत शेल व्यवहार के लिए अनुमति देते हैं: शेल शब्द विभाजन या pathname विस्तार, आदि के लिए मना कर सकेगा।

अब बिल्डरों और कीवर्ड की सूची देखें और यह पता लगाने की कोशिश करें कि कुछ को कीवर्ड की आवश्यकता क्यों है।


!एक कीवर्ड है। ऐसा लगता है कि एक समारोह के साथ अपने व्यवहार की नकल करना संभव होगा:

not() {
    if "$@"; then
        return false
    else
        return true
    fi
}

लेकिन इस तरह का निर्माण मना होगा:

$ ! ! true
$ echo $?
0

या

$ ! { true; }
echo $?
1

timeइसके लिए भी : यह एक कीवर्ड के लिए अधिक शक्तिशाली है ताकि यह जटिल यौगिक आदेशों और पाइपलाइनों को पुनर्निर्देशन के साथ समय दे सके:

$ time grep '^#' ~/.bashrc | { i=0; while read -r; do printf '%4d %s\n' "$((++i))" "$REPLY"; done; } > bashrc_numbered 2>/dev/null

यदि timeजहां एक मात्र कमांड (यहां तक ​​कि बिलिन) है, तो यह केवल तर्कों को देखेगा grep, ^#और /home/gniourf/.bashrc, इस समय, और फिर इसका आउटपुट पाइपलाइन के शेष हिस्सों से गुजरेगा। लेकिन एक कीवर्ड के साथ, बैश सब कुछ संभाल सकता है! यह timeपुनर्निर्देशन सहित पूरी पाइपलाइन कर सकता है! यदि timeहम केवल आदेश होते, तो हम ऐसा नहीं कर सकते थे:

$ time { printf 'hello '; echo world; }

कोशिश करो:

$ \time { printf 'hello '; echo world; }
bash: syntax error near unexpected token `}'

इसे ठीक करने का प्रयास करें ():

$ \time { printf 'hello '; echo world;
time: cannot run {: No such file or directory

निराशाजनक।


कीवर्ड बनाम उपनाम?

$ alias mytime=time
$ alias myls=ls
$ mytime myls

आपको क्या लगता है?


वास्तव में, एक बिलिन एक कमांड की तरह है, सिवाय इसके कि इसे शेल में बनाया गया है, जबकि एक कीवर्ड एक ऐसी चीज है जो परिष्कृत व्यवहार की अनुमति देता है! हम कह सकते हैं कि यह शेल के व्याकरण का हिस्सा है।


2
@ जॉनीटेक्स के साथ सहमत, यह सबसे व्यापक और उपयुक्त उत्तर है जो मैंने स्टैक साइटों पर देखा है। धन्यवाद। एक शायद असंबंधित सवाल: सिर्फ जिज्ञासा की खातिर मैं के साथ एक कमांड पूर्ववर्ती से 'अस्थायी रूप से अक्षम उर्फ' कार्यक्षमता के लिए प्रलेखन खोजने की कोशिश कर रहा हूँ =\'का उपयोग करके man, aproposऔर helpऔर मैं किसी भी भाग्य नहीं था। कोई भी विचार जहां मैं इस जानकारी को खोजने के बारे में जाऊंगा? ज्यादातर इसलिए कि भविष्य में मैं देख सकता हूं कि वहां और क्या है, क्योंकि मुझे लगता है कि मुझे एक संदर्भ स्रोत याद आ रहा है।
एन.सी.

@nc: आपको यह स्पष्ट रूप से प्रलेखित नहीं मिलेगा। इस जवाब में इसका कारण यह बताया गया है। निकटतम शेल आपको ऑपरेशन शेल ऑपरेशन के संदर्भ मैनुअल में मिलेगा । आप देखेंगे कि उर्फ ​​विस्तार बहुत जल्दी किया जाता है (कुछ मैंने इस उत्तर में जोर देने की कोशिश की), चरण 2 में। उद्धरण हटाने, पैरामीटर विस्तार, ग्लोबिंग, आदि बाद में किए जाते हैं। तो करने को अक्षम एक उपनाम है, तो आप को उद्धृत करते हुए किसी तरह का उपयोग कर सकते हैं न करे उपनाम के रूप में एक टोकन को समझने, जैसे, से खोल \ll, "ll"या 'll'
gniourf_gniourf

1
मुझे वास्तव में ऑर्डर की चीज मिली, एलियास और कीवर्ड को निकाल दिया गया जो पहले होता है। चूँकि हम [[पैदावार को उद्धृत करते हैं, इसलिए \[[यह उपनाम के रूप में प्राप्त नहीं होता है। अभी तक ठीक है? जहाँ मैं हार गया था, उसे एहसास नहीं हो रहा था कि बैकलैश बैश में एक चौकाने वाली बात थी, और मैंने इसे एलियास और कीवर्ड के तहत देखने की कोशिश की और पूरी तरह से हार गया ... अब सब ठीक है। कोटिंग सेक्शन के तहत:> एक गैर-उद्धृत बैकस्लैश () एस्केप चरित्र है।
एन.सी.

1
तो हम उस (2) के बारे में सोच सकते हैं कि ओप सूची में \[[टोकन के रूप में, और एक एकल टोकन है जो कि लिटरेलाक्वाटेक्टोकन के प्रकार का है, [[जिसके विपरीत एक ओपनटेस्टकॉर्डरटोकन होगा, और ]]जिसके लिए oroper संकलन / सही सिंटैक्स के लिए एक क्लोजिंग TTestKeywordToken की आवश्यकता होती है । बाद में, (4) लिटरलक्वाइनटोटेकेन का मूल्यांकन करने [[के लिए बुलिटिन / कमांड के नाम के रूप में मूल्यांकन किया जाएगा , और (6) बैश बारफ होगा , क्योंकि कोई [[बिलिन या कमांड नहीं है। अच्छा लगा। मैं समय के साथ सटीक विवरण भूल सकता हूं, लेकिन इस समय बैश जिस तरह से सामान चलाता है वह मेरे लिए बहुत स्पष्ट है; धन्यवाद।
एन.सी.

9

man bashउन्हें कॉल करता है SHELL BUILTIN COMMANDS। तो, एक "शेल बिल्डिन" एक सामान्य कमांड की तरह है grep, जैसे , आदि, लेकिन एक अलग फाइल में समाहित होने के बजाय, इसे बैश में ही बनाया गया है । यह उन्हें बाहरी आदेशों की तुलना में अधिक कुशलता से प्रदर्शन करता है।

एक कीवर्ड "बैश में हार्ड-कोडेड भी है, लेकिन एक बिलिन के विपरीत, एक कीवर्ड अपने आप में एक कमांड नहीं है, लेकिन एक कमांड निर्माण का एक सबयूनिट है।" मैं इसका अर्थ यह समझाता हूं कि कीवर्ड का कोई कार्य अकेले नहीं है, लेकिन कुछ भी करने के लिए कमांड की आवश्यकता होती है। (लिंक से, अन्य उदाहरण हैं for, while, do, और !, और देखते हैं में और अधिक मेरा उत्तर अपने अन्य प्रश्न के।)


1
दिलचस्प तथ्य: [[ is a shell keywordलेकिन [ is a shell builtin। मुझे कोई जानकारी नहीं है की क्यों।
स्पार्कवॉक

1
यह ऐतिहासिक कारणों और POSIX मानक के लिए संभव है कि पुराने बॉर्न शेल को जितना संभव हो सके, [दिन में अलग-अलग कमांड के रूप में अस्तित्व में लाया जाए। [[मानक द्वारा निर्दिष्ट नहीं किया जाता है, इसलिए डेवलपर्स इसे कीवर्ड के रूप में या अंतर्निहित के रूप में शामिल करना चुन सकते हैं।
सर्गी कोलोडियाज़नी

1

कमांड लाइन मैनुअल जो उबंटू के साथ आता है, वह कीवर्ड की परिभाषा नहीं देता है, हालांकि ऑनलाइन मैनुअल (सिडेनोट देखें) और पॉसिक शेल कमांड लैंग्वेज स्टैंडर्ड स्पेसिफिकेशन्स , इन्हें "आरक्षित शब्द" के रूप में संदर्भित करते हैं, और दोनों ही उन की सूची प्रदान करते हैं। POSIX मानक से:

यह मान्यता तब होगी जब कोई भी वर्ण उद्धृत नहीं किया जाता है और जब इस शब्द का उपयोग किया जाता है:

  • एक कमांड का पहला शब्द

  • मामला, के लिए, या के अलावा अन्य आरक्षित शब्दों में से एक के बाद पहला शब्द

  • केस कमांड में तीसरा शब्द (केवल इस मामले में मान्य है)

  • कमांड के लिए तीसरा शब्द (केवल और केवल इस मामले में मान्य हैं)

यहां कुंजी यह है कि कीवर्ड / आरक्षित शब्दों का विशेष अर्थ है क्योंकि वे शेल सिंटैक्स की सुविधा देते हैं, कोड के कुछ ब्लॉक जैसे कि लूप्स, कम्पाउंड कमांड, ब्रांचिंग (यदि / केस) स्टेटमेंट आदि को इंगित करने के लिए सेवा करते हैं, तो वे कमांड स्टेटमेंट बनाने की अनुमति देते हैं, लेकिन अपने आप से - कुछ भी न करें, और वास्तव में यदि आप कीवर्ड दर्ज करते हैं for, जैसे कि until, case- शेल एक पूर्ण विवरण की अपेक्षा करेगा, अन्यथा - विशेष विवरण:

$ for
bash: syntax error near unexpected token `newline'
$  

स्रोत कोड स्तर पर, बैश के लिए आरक्षित शब्द parese.y में परिभाषित किए गए हैं , जबकि बिल्ट-इन में पूरी निर्देशिका उनके लिए समर्पित है।

पक्षीय लेख

GNU इंडेक्स [आरक्षित शब्द के रूप में दिखाता है , हालांकि यह इन-बिल्ट-इन-कमांड है। [[इसके विपरीत एक आरक्षित शब्द है।

यह भी देखें: कीवर्ड, आरक्षित शब्द और बिलिन के बीच अंतर?

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