जब मैं इन दोनों आदेशों को चलाता हूं, मुझे मिलता है
$ type cd
cd is a shell builtin
$ type if
if is a shell keyword
यह स्पष्ट रूप से दिखाया गया है कि cdशेल शेल है और ifशेल कीवर्ड है। तो शेल बिल्ड और कीवर्ड के बीच अंतर क्या है?
जब मैं इन दोनों आदेशों को चलाता हूं, मुझे मिलता है
$ type cd
cd is a shell builtin
$ type if
if is a shell keyword
यह स्पष्ट रूप से दिखाया गया है कि cdशेल शेल है और ifशेल कीवर्ड है। तो शेल बिल्ड और कीवर्ड के बीच अंतर क्या है?
जवाबों:
बैश और कीवर्ड के बीच एक मजबूत अंतर है, जिस तरह से बैश आपके कोड को पार्स करता है। इससे पहले कि हम अंतर के बारे में बात करें, आइए सभी खोजशब्दों और बिल्डरों को सूचीबद्ध करें:
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
आपको क्या लगता है?
वास्तव में, एक बिलिन एक कमांड की तरह है, सिवाय इसके कि इसे शेल में बनाया गया है, जबकि एक कीवर्ड एक ऐसी चीज है जो परिष्कृत व्यवहार की अनुमति देता है! हम कह सकते हैं कि यह शेल के व्याकरण का हिस्सा है।
=\'का उपयोग करके man, aproposऔर helpऔर मैं किसी भी भाग्य नहीं था। कोई भी विचार जहां मैं इस जानकारी को खोजने के बारे में जाऊंगा? ज्यादातर इसलिए कि भविष्य में मैं देख सकता हूं कि वहां और क्या है, क्योंकि मुझे लगता है कि मुझे एक संदर्भ स्रोत याद आ रहा है।
\ll, "ll"या 'll'।
[[पैदावार को उद्धृत करते हैं, इसलिए \[[यह उपनाम के रूप में प्राप्त नहीं होता है। अभी तक ठीक है? जहाँ मैं हार गया था, उसे एहसास नहीं हो रहा था कि बैकलैश बैश में एक चौकाने वाली बात थी, और मैंने इसे एलियास और कीवर्ड के तहत देखने की कोशिश की और पूरी तरह से हार गया ... अब सब ठीक है। कोटिंग सेक्शन के तहत:> एक गैर-उद्धृत बैकस्लैश () एस्केप चरित्र है।
\[[टोकन के रूप में, और एक एकल टोकन है जो कि लिटरेलाक्वाटेक्टोकन के प्रकार का है, [[जिसके विपरीत एक ओपनटेस्टकॉर्डरटोकन होगा, और ]]जिसके लिए oroper संकलन / सही सिंटैक्स के लिए एक क्लोजिंग TTestKeywordToken की आवश्यकता होती है । बाद में, (4) लिटरलक्वाइनटोटेकेन का मूल्यांकन करने [[के लिए बुलिटिन / कमांड के नाम के रूप में मूल्यांकन किया जाएगा , और (6) बैश बारफ होगा , क्योंकि कोई [[बिलिन या कमांड नहीं है। अच्छा लगा। मैं समय के साथ सटीक विवरण भूल सकता हूं, लेकिन इस समय बैश जिस तरह से सामान चलाता है वह मेरे लिए बहुत स्पष्ट है; धन्यवाद।
man bashउन्हें कॉल करता है SHELL BUILTIN COMMANDS। तो, एक "शेल बिल्डिन" एक सामान्य कमांड की तरह है grep, जैसे , आदि, लेकिन एक अलग फाइल में समाहित होने के बजाय, इसे बैश में ही बनाया गया है । यह उन्हें बाहरी आदेशों की तुलना में अधिक कुशलता से प्रदर्शन करता है।
एक कीवर्ड "बैश में हार्ड-कोडेड भी है, लेकिन एक बिलिन के विपरीत, एक कीवर्ड अपने आप में एक कमांड नहीं है, लेकिन एक कमांड निर्माण का एक सबयूनिट है।" मैं इसका अर्थ यह समझाता हूं कि कीवर्ड का कोई कार्य अकेले नहीं है, लेकिन कुछ भी करने के लिए कमांड की आवश्यकता होती है। (लिंक से, अन्य उदाहरण हैं for, while, do, और !, और देखते हैं में और अधिक मेरा उत्तर अपने अन्य प्रश्न के।)
[[ is a shell keywordलेकिन [ is a shell builtin। मुझे कोई जानकारी नहीं है की क्यों।
[दिन में अलग-अलग कमांड के रूप में अस्तित्व में लाया जाए। [[मानक द्वारा निर्दिष्ट नहीं किया जाता है, इसलिए डेवलपर्स इसे कीवर्ड के रूप में या अंतर्निहित के रूप में शामिल करना चुन सकते हैं।
कमांड लाइन मैनुअल जो उबंटू के साथ आता है, वह कीवर्ड की परिभाषा नहीं देता है, हालांकि ऑनलाइन मैनुअल (सिडेनोट देखें) और पॉसिक शेल कमांड लैंग्वेज स्टैंडर्ड स्पेसिफिकेशन्स , इन्हें "आरक्षित शब्द" के रूप में संदर्भित करते हैं, और दोनों ही उन की सूची प्रदान करते हैं। POSIX मानक से:
यह मान्यता तब होगी जब कोई भी वर्ण उद्धृत नहीं किया जाता है और जब इस शब्द का उपयोग किया जाता है:
एक कमांड का पहला शब्द
मामला, के लिए, या के अलावा अन्य आरक्षित शब्दों में से एक के बाद पहला शब्द
केस कमांड में तीसरा शब्द (केवल इस मामले में मान्य है)
कमांड के लिए तीसरा शब्द (केवल और केवल इस मामले में मान्य हैं)
यहां कुंजी यह है कि कीवर्ड / आरक्षित शब्दों का विशेष अर्थ है क्योंकि वे शेल सिंटैक्स की सुविधा देते हैं, कोड के कुछ ब्लॉक जैसे कि लूप्स, कम्पाउंड कमांड, ब्रांचिंग (यदि / केस) स्टेटमेंट आदि को इंगित करने के लिए सेवा करते हैं, तो वे कमांड स्टेटमेंट बनाने की अनुमति देते हैं, लेकिन अपने आप से - कुछ भी न करें, और वास्तव में यदि आप कीवर्ड दर्ज करते हैं for, जैसे कि until, case- शेल एक पूर्ण विवरण की अपेक्षा करेगा, अन्यथा - विशेष विवरण:
$ for
bash: syntax error near unexpected token `newline'
$
स्रोत कोड स्तर पर, बैश के लिए आरक्षित शब्द parese.y में परिभाषित किए गए हैं , जबकि बिल्ट-इन में पूरी निर्देशिका उनके लिए समर्पित है।
GNU इंडेक्स [आरक्षित शब्द के रूप में दिखाता है , हालांकि यह इन-बिल्ट-इन-कमांड है। [[इसके विपरीत एक आरक्षित शब्द है।
यह भी देखें: कीवर्ड, आरक्षित शब्द और बिलिन के बीच अंतर?