बैश लिपियों के लिए एक शब्दार्थ?


87

किसी भी अन्य भाषा से अधिक, जो मुझे पता है, मैंने हर बार जब मुझे किसी छोटी सी चीज की जरूरत होती है, तो मैंने "सीख" लिया है। नतीजतन, मैं छोटी स्क्रिप्ट्स को एक साथ पैचवर्क कर सकता हूं जो काम करने के लिए दिखाई देती हैं। हालाँकि, मैं वास्तव में नहीं जानता कि क्या चल रहा है, और मैं प्रोग्रामिंग भाषा के रूप में बैश के लिए और अधिक औपचारिक परिचय की उम्मीद कर रहा था। उदाहरण के लिए: मूल्यांकन आदेश क्या है? स्कूपिंग नियम क्या हैं? टाइपिंग डिसिप्लिन क्या है, जैसे सब कुछ एक स्ट्रिंग है? कार्यक्रम की स्थिति क्या है - क्या यह चर नामों के लिए स्ट्रिंग्स का एक महत्वपूर्ण मूल्य है; वहाँ से अधिक है, जैसे ढेर? क्या कोई ढेर है? और इसी तरह।

मैंने इस तरह की अंतर्दृष्टि के लिए जीएनयू बैश मैनुअल से परामर्श करने के लिए सोचा, लेकिन यह नहीं लगता कि मैं क्या चाहता हूं; यह कोर सिमेंटिक मॉडल के स्पष्टीकरण के बजाय सिंटैक्टिक चीनी के कपड़े धोने की सूची से अधिक है। मिलियन-एंड-वन "बैश ट्यूटोरियल" ऑनलाइन केवल बदतर हैं। शायद मुझे पहले अध्ययन करना चाहिए sh, और बैश को इस के शीर्ष पर एक वाक्यात्मक चीनी के रूप में समझना चाहिए ? मुझे नहीं पता कि यह एक सटीक मॉडल है, हालांकि।

कोई सुझाव?

संपादित करें: मुझे आदर्श रूप से जो मैं देख रहा हूं उसके उदाहरण प्रदान करने के लिए कहा गया है। "औपचारिक शब्दार्थ" पर मैं क्या विचार करूंगा इसका एक चरम उदाहरण "जावास्क्रिप्ट का सार" पर यह पेपर है । शायद थोड़ा कम औपचारिक उदाहरण हास्केल 2010 की रिपोर्ट है


3
क्या उन्नत बैश स्क्रिप्टिंग गाइड "मिलियन और वन" में से एक है?
चोराबा

2
मुझे यकीन नहीं है कि बैश में एक "मूल अर्थ मॉडल" है (ठीक है, शायद "लगभग सब कुछ एक स्ट्रिंग है"); मुझे लगता है कि यह वास्तव में सभी प्रकार की चीनी है।
गॉर्डन डेविसन

4
जिसे आप "सिंटैक्टिक शुगर की एक कपड़े धोने की सूची" कहते हैं, वास्तव में विस्तार का शब्दार्थ मॉडल है - निष्पादन का एक अत्यंत महत्वपूर्ण हिस्सा। 90% बग और भ्रम विस्तार मॉडल को नहीं समझने के कारण है।
वह अन्य लड़का

4
मैं देख सकता हूं कि कोई यह क्यों सोच सकता है कि यह एक व्यापक प्रश्न है यदि आप इसे पढ़ते हैं जैसे मैं एक शेल स्क्रिप्ट कैसे लिखूं ? लेकिन असली सवाल यह है कि विशेष रूप से शेल भाषा और बैश के लिए औपचारिक शब्दार्थ और आधार क्या हैं? , और यह एक सुसंगत उत्तर के साथ एक अच्छा सवाल है। फिर से मतदान करना।
कोजिरो

1
मैंने linuxcommand.org पर काफी कुछ सीखा है और कमांड लाइन पर एक और अधिक गहन पुस्तक का एक मुफ्त पीडीएफ भी है और शेल स्क्रिप्ट लिख रहा है
20

जवाबों:


107

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

शेल के सिंटैक्स की दूसरी जड़ इसकी परवरिश से अलग-अलग UNIX उपयोगिताओं की एक मिशमा के रूप में आती है। शेल में अक्सर निर्मित होने वाले अधिकांश वास्तव में बाहरी आदेशों के रूप में लागू किए जा सकते हैं। यह लूप के लिए कई शेल नियोफाइट्स फेंकता है जब उन्हें पता चलता है कि /bin/[कई प्रणालियों पर मौजूद है।

$ if '/bin/[' -f '/bin/['; then echo t; fi # Tested as-is on OS X, without the `]`
t

वाट?

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

#!/usr/bin/env python

from __future__ import print_function
import os, sys

'''Hacky barebones shell.'''

try:
  input=raw_input
except NameError:
  pass

def main():
  while True:
    cmd = input('prompt> ')
    args = cmd.split()
    if not args:
      continue
    cpid = os.fork()
    if cpid == 0:
      # We're in a child process
      os.execl(args[0], *args)
    else:
      os.waitpid(cpid, 0)

if __name__ == '__main__':
  main()

मुझे आशा है कि ऊपर स्पष्ट है कि शेल का निष्पादन मॉडल बहुत अधिक है:

1. Expand words.
2. Assume the first word is a command.
3. Execute that command with the following words as arguments.

विस्तार, कमान संकल्प, निष्पादन। शेल के सभी शब्दार्थ इन तीन चीजों में से एक में बंधे हुए हैं, हालांकि वे कार्यान्वयन के मुकाबले कहीं अधिक समृद्ध हैं जो मैंने ऊपर लिखा था।

सभी कमांड नहीं fork। वास्तव में, कुछ मुट्ठी भर आदेश ऐसे होते हैं जो बाह्य रूप में लागू किए गए एक टन का अर्थ नहीं करते हैं (जैसे कि उन्हें करना होगा fork), लेकिन यहां तक ​​कि वे अक्सर सख्त पॉसिक्स अनुपालन के लिए बाह्य के रूप में उपलब्ध होते हैं।

बैश ने POSIX शेल को बढ़ाने के लिए नई विशेषताओं और कीवर्ड को जोड़कर इस आधार का निर्माण किया। यह श के साथ लगभग संगत है, और बैश इतना सर्वव्यापी है कि कुछ स्क्रिप्ट लेखकों को यह एहसास किए बिना वर्षों चले जाते हैं कि स्क्रिप्ट वास्तव में पोस्किली सख्त प्रणाली पर काम नहीं कर सकती है। (मुझे यह भी आश्चर्य है कि लोग एक प्रोग्रामिंग भाषा के शब्दार्थ और शैली के बारे में इतना कैसे ध्यान रख सकते हैं, और शेल के शब्दार्थ और शैली के लिए बहुत कम हैं, लेकिन मैं विचलन करता हूं।)

मूल्यांकन का आदेश

यह एक ट्रिक प्रश्न है: बैश अपने प्राथमिक सिंटैक्स में अभिव्यक्तियों को बाएं से दाएं की व्याख्या करता है, लेकिन अंकगणितीय सिंटैक्स में यह सी पूर्वता का अनुसरण करता है। अभिव्यक्ति विस्तार से अलग है , यद्यपि। EXPANSIONमार मैनुअल के अनुभाग से:

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

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

क्षेत्र

कार्यक्षेत्र गुंजाइश

पुराने ECMAscript की तरह, शेल में डायनेमिक स्कोप होता है जब तक कि आप स्पष्ट रूप से किसी फ़ंक्शन के भीतर नामों की घोषणा नहीं करते हैं।

$ foo() { echo $x; }
$ bar() { local x; echo $x; }
$ foo

$ bar

$ x=123
$ foo
123
$ bar

$ …

पर्यावरण और प्रक्रिया "गुंजाइश"

सबस्क्रिप्शन उनके पैरेंट शेल के वेरिएबल को इनहेरिट करता है, लेकिन अन्य प्रकार की प्रक्रियाएं अनएक्सपोर्ट किए गए नामों को प्राप्त नहीं करती हैं।

$ x=123
$ ( echo $x )
123
$ bash -c 'echo $x'

$ export x
$ bash -c 'echo $x'
123
$ y=123 bash -c 'echo $y' # another way to transiently export a name
123

आप इन स्कूपिंग नियमों को जोड़ सकते हैं:

$ foo() {
>   local -x bar=123 # Export foo, but only in this scope
>   bash -c 'echo $bar'
> }
$ foo
123
$ echo $bar

$

टंकण अनुशासन

उम, प्रकार। हाँ। बैश वास्तव में प्रकार नहीं है, और सब कुछ एक स्ट्रिंग में फैलता है (या शायद एक शब्द अधिक उपयुक्त होगा।) लेकिन आइए विभिन्न प्रकार के विस्तार की जांच करें।

स्ट्रिंग्स

बहुत कुछ भी एक स्ट्रिंग के रूप में माना जा सकता है। बैश में बेयरिंग्स तार होते हैं जिनका अर्थ पूरी तरह से उस पर लागू विस्तार पर निर्भर करता है।

कोई विस्तार नहीं

यह प्रदर्शित करना सार्थक हो सकता है कि एक नंगे शब्द वास्तव में सिर्फ एक शब्द है, और यह उद्धरण उस बारे में कुछ भी नहीं बदलता है।

$ echo foo
foo
$ 'echo' foo
foo
$ "echo" foo
foo
पदार्थ का विस्तार
$ fail='echoes'
$ set -x # So we can see what's going on
$ "${fail:0:-2}" Hello World
+ echo Hello World
Hello World

विस्तार पर अधिक जानकारी के लिए, Parameter Expansionमैनुअल के सेक्शन को पढ़ें । यह काफी शक्तिशाली है।

पूर्णांक और अंकगणित के भाव

आप समकोण विशेषता के साथ नाम लिख सकते हैं शेल को असाइनमेंट अभिव्यक्तियों के दाहिने हाथ की तरफ अंकगणित के रूप में बता सकते हैं। फिर, जब पैरामीटर का विस्तार होता है, तो इसे एक स्ट्रिंग ... के विस्तार से पहले पूर्णांक गणित के रूप में मूल्यांकन किया जाएगा।

$ foo=10+10
$ echo $foo
10+10
$ declare -i foo
$ foo=$foo # Must re-evaluate the assignment
$ echo $foo
20
$ echo "${foo:0:1}" # Still just a string
2

Arrays

तर्क और स्थितिगत पैरामीटर

सरणियों के बारे में बात करने से पहले यह स्थितिगत मापदंडों पर चर्चा करने के लायक हो सकती है। शेल स्क्रिप्ट की दलीलों को गिने हुए मापदंडों, $1और $2, $3आदि का उपयोग करके एक्सेस किया जा सकता है । आप इन सभी मापदंडों को एक ही बार में उपयोग कर सकते हैं "$@", जिसमें विस्तार में सरणियों के साथ कई चीजें हैं। आप की स्थापना की और का उपयोग कर स्थितीय मापदंडों को बदल सकते हैं setया shift, या बस खोल या इन मानकों के साथ एक खोल समारोह लागू द्वारा builtins:

$ bash -c 'for ((i=1;i<=$#;i++)); do
>   printf "\$%d => %s\n" "$i" "${@:i:1}"
> done' -- foo bar baz
$1 => foo
$2 => bar
$3 => baz
$ showpp() {
>   local i
>   for ((i=1;i<=$#;i++)); do
>     printf '$%d => %s\n' "$i" "${@:i:1}"
>   done
> }
$ showpp foo bar baz
$1 => foo
$2 => bar
$3 => baz
$ showshift() {
>   shift 3
>   showpp "$@"
> }
$ showshift foo bar baz biz quux xyzzy
$1 => biz
$2 => quux
$3 => xyzzy

बैश मैनुअल कभी-कभी $0एक स्थितिगत पैरामीटर के रूप में भी संदर्भित होता है। मुझे यह भ्रामक लगता है, क्योंकि यह इसे तर्क गिनती में शामिल नहीं करता है $#, लेकिन यह एक गिना हुआ पैरामीटर है, इसलिए meh। $0शेल या वर्तमान शेल स्क्रिप्ट का नाम है।

Arrays

सरणियों के सिंटैक्स को स्थितीय मापदंडों के बाद तैयार किया जाता है, इसलिए यदि आप चाहें तो एक बाहरी प्रकार के "बाहरी स्थितीय मापदंडों" के रूप में सरणियों के बारे में सोचना ज्यादातर स्वस्थ है। निम्न दृष्टिकोणों का उपयोग करके ऐरे को घोषित किया जा सकता है:

$ foo=( element0 element1 element2 )
$ bar[3]=element3
$ baz=( [12]=element12 [0]=element0 )

आप सरणी तत्वों को अनुक्रमणिका द्वारा एक्सेस कर सकते हैं:

$ echo "${foo[1]}"
element1

आप ऐरे को स्लाइस कर सकते हैं:

$ printf '"%s"\n' "${foo[@]:1}"
"element1"
"element2"

यदि आप एक सरणी को एक सामान्य पैरामीटर के रूप में मानते हैं, तो आपको शून्य सूचकांक प्राप्त होगा।

$ echo "$baz"
element0
$ echo "$bar" # Even if the zeroth index isn't set

$ …

यदि आप शब्दों को रोकने के लिए उद्धरण या बैकस्लैश का उपयोग करते हैं, तो सरणी निर्दिष्ट शब्दों को बनाए रखेगा:

$ foo=( 'elementa b c' 'd e f' )
$ echo "${#foo[@]}"
2

सरणियों और स्थितिगत मापदंडों के बीच मुख्य अंतर हैं:

  1. स्थितिगत पैरामीटर विरल नहीं हैं। यदि $12सेट किया गया है, तो आप सुनिश्चित कर सकते हैं कि $11सेट किया गया है, भी। (यह खाली स्ट्रिंग पर सेट किया जा सकता है, लेकिन $#12. से छोटा नहीं होगा।) यदि "${arr[12]}"सेट किया गया है, तो इसकी कोई गारंटी नहीं है कि "${arr[11]}"सेट किया गया है, और सरणी की लंबाई 1 जितनी हो सकती है।
  2. किसी सरणी का शून्य तत्व स्पष्ट रूप से उस सरणी का शून्य तत्व है। स्थितिगत मापदंडों में, शून्य तत्व पहला तर्क नहीं है , लेकिन शेल या शेल स्क्रिप्ट का नाम है।
  3. करने के लिए shiftएक सरणी, आप टुकड़ा करने के लिए है और पुन: असाइन, की तरह arr=( "${arr[@]:1}" )। आप भी कर सकते हैं unset arr[0], लेकिन यह इंडेक्स 1 में पहला तत्व बना देगा।
  4. गोलाकार के रूप में शेल फ़ंक्शन के बीच एरे को स्पष्ट रूप से साझा किया जा सकता है, लेकिन आपको इसे देखने के लिए शेल फ़ंक्शन के लिए स्पष्ट रूप से स्थितीय मापदंडों को पास करना होगा।

फ़ाइल नाम के सरणियों को बनाने के लिए पथनाम विस्तार का उपयोग करना अक्सर सुविधाजनक होता है:

$ dirs=( */ )

आदेश

कमांड प्रमुख हैं, लेकिन वे मैनुअल की तुलना में बेहतर गहराई में शामिल हैं। SHELL GRAMMARअनुभाग पढ़ें । विभिन्न प्रकार के आदेश हैं:

  1. साधारण कमांड (जैसे $ startx)
  2. पाइपलाइन (जैसे $ yes | make config) (योग्य)
  3. सूचियाँ (जैसे $ grep -qF foo file && sed 's/foo/bar/' file > newfile)
  4. यौगिक कमांड (जैसे $ ( cd -P /var/www/webroot && echo "webroot is $PWD" ))
  5. Coprocesses (जटिल, कोई उदाहरण नहीं)
  6. कार्य (एक साधारण कमांड के रूप में माना जा सकता है एक मिश्रित कमांड)

निष्पादन मॉडल

पाठ्यक्रम के निष्पादन मॉडल में ढेर और ढेर दोनों शामिल हैं। यह सभी यूनिक्स कार्यक्रमों के लिए स्थानिक है। बैश में शेल फ़ंक्शन के लिए कॉल स्टैक भी है, जो callerबिलिन के नेस्टेड उपयोग के माध्यम से दिखाई देता है ।

संदर्भ:

  1. SHELL GRAMMARबाश मैनुअल का अनुभाग
  2. XCU शेल कमांड भाषा प्रलेखन
  3. बैश गाइड Greycat के विकि पर।
  4. UNIX पर्यावरण में उन्नत प्रोग्रामिंग

कृपया टिप्पणी करें यदि आप चाहते हैं कि मैं एक विशिष्ट दिशा में और विस्तार करूं।


16
+1: शानदार व्याख्या। उदाहरणों के साथ इसे लिखने में बिताए समय की सराहना करें।
जयपाल सिंह

+1 yes | make config;-) लेकिन गंभीरता से, एक बहुत अच्छा लेखन।
डिजिटल ट्रॉमा

बस यह पढ़ना शुरू कर दिया .. अच्छा। कुछ टिप्पणी छोड़ देंगे। 1) एक और भी बड़ा आश्चर्य तब होता है जब आप उसे देखते हैं /bin/[और /bin/testअक्सर एक ही एप्लीकेशनटन होता है 2) "पहले शब्द को एक कमांड मानें।" - उम्मीद है कि जब आप असाइनमेंट करेंगे ...
Karoly Horvath

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

@kojiro: nah कि यह बस अधिक जटिल होगा, यह निश्चित रूप से मेरा इरादा नहीं था! लेकिन असाइनमेंट थोड़ा अलग तरीके से काम करता है (x), और IMHO आपको इसका पाठ में कहीं उल्लेख करना चाहिए। (x): और कुछ भ्रम का एक स्रोत ... मैं अब यह भी नहीं गिन सकता कि मैंने कितनी बार लोगों को a = 1काम न करने के लिए मजबूर किया।
कारोली होर्वाथ

5

आपके प्रश्न का उत्तर "टाइपिंग अनुशासन क्या है, उदाहरण के लिए सब कुछ एक स्ट्रिंग है" बैश चर चरित्र के तार हैं। लेकिन, बैश अंकगणित संचालन और चर पर तुलना करते हैं जब चर पूर्णांक होते हैं। बाश चर को नियंत्रित करने के लिए अपवाद वर्ण स्ट्रिंग हैं जब कहा जाता है कि चर प्रकार हैं या अन्यथा घोषित किए गए हैं

$ A=10/2
$ echo "A = $A"           # Variable A acting like a String.
A = 10/2

$ B=1
$ let B="$B+1"            # Let is internal to bash.
$ echo "B = $B"           # One is added to B was Behaving as an integer.
B = 2

$ A=1024                  # A Defaults to string
$ B=${A/24/STRING01}      # Substitute "24"  with "STRING01".
$ echo "B = $B"           # $B STRING is a string
B = 10STRING01

$ B=${A/24/STRING01}      # Substitute "24"  with "STRING01".
$ declare -i B
$ echo "B = $B"           # Declaring a variable with non-integers in it doesn't change the contents.
B = 10STRING01

$ B=${B/STRING01/24}      # Substitute "STRING01"  with "24".
$ echo "B = $B"
B = 1024

$ declare -i B=10/2       # Declare B and assigning it an integer value
$ echo "B = $B"           # Variable B behaving as an Integer
B = 5

विकल्प विकल्प घोषित करें:

  • -एक चर एक सरणी है।
  • केवल फ़ंक्शन नाम का उपयोग करें।
  • -i चर को पूर्णांक माना जाता है; जब अंक का मान दिया जाता है तो अंकगणितीय मूल्यांकन किया जाता है।
  • -p प्रत्येक चर की विशेषताओं और मूल्यों को प्रदर्शित करें। जब -p का उपयोग किया जाता है, तो अतिरिक्त विकल्पों पर ध्यान नहीं दिया जाता है।
  • -r चर केवल पढ़ने के लिए। इन चरों को बाद में असाइनमेंट स्टेटमेंट्स द्वारा मान नहीं सौंपा जा सकता है, न ही वे परेशान हो सकते हैं।
  • -प्रत्येक चर ट्रेस विशेषता दे।
  • -x पर्यावरण के माध्यम से बाद के आदेशों के निर्यात के लिए प्रत्येक चर को चिह्नित करें।

1

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

एफडब्ल्यूआईडब्ल्यू, मेरा अनुभव आपका जैसा रहा है; हालाँकि विभिन्न किताबें (जैसे, ओ'रिली "लर्निंग द बैश शेल" और इसी तरह) सिंटैक्स के साथ मदद करती हैं, विभिन्न समस्याओं को हल करने के बहुत सारे अजीब तरीके हैं, और उनमें से कुछ पुस्तक में नहीं हैं और उन्हें गुगली करना होगा।

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