श लूप में "डू" के बाद "क्यों नहीं है?"


28

एक पंक्ति पर लिखे ;जाने के बाद doशेल लूप्स में वर्ण क्यों नहीं है ?

यहाँ मेरा मतलब है। जब कई लाइनों पर लिखा जाता है, तो एक forलूप दिखता है:

$ for i in $(jot 2)
> do
>     echo $i
> done

और एक लाइन पर:

$ for i in $(jot 2); do echo $i; done

सभी संक्षिप्त पंक्तियों के एक मिल ;उनके पीछे छोड़कर के लिए doलाइन, और यदि आप में शामिल ;है, यह एक त्रुटि है। शायद किसी ने मुझसे बहुत ज्यादा होशियार होने की बात कही है कि यह एक कारण के लिए सही बात थी, लेकिन मुझे पता नहीं है कि कारण क्या है। यह मुझे असंगत लगता है।

whileछोरों के साथ भी ऐसा ही है।

$ while something
> do
>     anotherthing
> done
$ while something; do anotherthing; done


2
यह सुसंगत है: while/ के बाद कोई अर्धविराम नहीं है for
दिमित्री ग्रिगोरीव

जो चीज तुरंत ध्यान में आती है, वह यह है कि यह जरूरी नहीं है। कहीं और, अर्धविराम बयानों को अलग करते हैं।
पॉल ड्रेपर

क्योंकि यह बेमानी होगी। इसके बिना कोई अस्पष्टता नहीं है।
user207421

जवाबों:


29

यह कमांड का सिंटैक्स है। कम्पाउंड कमांड देखें

for name [ [in [words …] ] ; ] do commands; done

विशेष रूप से ध्यान दें: do commands

अधिकांश लोगों ने आसान पठनीयता की अनुमति देने के लिए एक अलग लाइन पर doऔर डाल दिया, commandsलेकिन यह आवश्यक नहीं है, आप लिख सकते हैं:

for i in thing
do something
done

मुझे पता है कि यह प्रश्न विशेष रूप से शेल के बारे में है और मैं बैश मैनुअल से जुड़ा हुआ हूं। यह शेल मैनुअल में उस तरह से नहीं लिखा गया है, बल्कि स्टीफन बॉर्न द्वारा बाइट पत्रिका के लिए लिखे गए लेख में लिखा गया है

स्टीफन कहते हैं:

एक कमांड सूची एक या अधिक सरल आदेशों का एक अनुक्रम है जिसे एक नई रेखा या ;अर्धविराम द्वारा अलग या समाप्त किया जाता है । इसके अलावा, सुरक्षित जैसे शब्दों करते और किया सामान्य रूप से एक नई पंक्ति से पहले कर रहे हैं या ;... में हर बार आदेश सूची निम्नलिखित बारी करते निष्पादित किया जाता है।


5
यह भी दिलचस्प होगा कि अर्धविराम क्यों नहीं होना चाहिए , जैसे for i in thing; do; something; done। पर्याप्त रूप से एक लाइन ब्रेक की अनुमति है, एक अर्धविराम की अनुमति नहीं है।
9

@ गीदड़: हाँ, बिल्कुल। इस प्रकार शेल व्याकरण की संरचना भी की गई है। somethingविषय है और doइसे करने के लिए लागू होता है। जैसे अंग्रेजी वाक्य संरचना में।
पीटर कॉर्ड्स

@gidds एक शाब्दिक (या सिंटैक्स का कोई अन्य टुकड़ा) आवश्यक है क्योंकि कई कमांड स्थिति में ( whileवाक्य रचना में) जा सकते हैं , इसलिए आपको लूप बॉडी कमांड से कंडीशन कमांड को अलग करने के लिए कुछ चाहिए। doउन्हें अलग करने के लिए उपयोग करना संभवतः वही है जो सबसे अधिक उपयुक्त लगता था।
JoL

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

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

12

मुझे नहीं पता कि इस वाक्यविन्यास का मूल कारण क्या है, लेकिन आइए इस तथ्य पर विचार करें कि whileलूप्स हालत अनुभाग में कई कमांड ले सकते हैं, जैसे।

while a=$(somecmd);
      [ -n "$a" ];
do
    echo "$a"
done

यहां, doलूप के कंडीशन सेक्शन और मुख्य बॉडी को अलग करने के लिए कीवर्ड आवश्यक है। doएक कीवर्ड जैसा है while, ifऔर then(और done), और यह दूसरों के अनुरूप प्रतीत होता है कि इसके बाद अर्धविराम या न्यूलाइन की आवश्यकता नहीं है, लेकिन एक कमांड के तुरंत पहले दिखाई देता है।

वैकल्पिक (सामान्यीकृत ifऔर while) कुछ बदसूरत दिखेंगे, हमें उदा

if; [ -n "$a" ]; then
    some command here
fi

forछोरों का वाक्य-विन्यास समान है।


11

शैल सिंटैक्स उपसर्ग आधारित है। इसमें विशेष कीवर्ड द्वारा पेश किए गए खंड हैं। कुछ खंडों को एक साथ जाना है।

एक whileलूप को एक या अधिक परीक्षण कमांड से बनाया जाता है:

test ; test ; test ; ...

और एक या अधिक बॉडी कमांड द्वारा:

body ; body ; body ; ...

कुछ को शेल को बताना पड़ता है कि थोड़ी देर से लूप शुरू होता है। यह whileशब्द का उद्देश्य है :

while test ; test ; test ; ...

लेकिन फिर, चीजें अस्पष्ट हैं। शरीर का प्रारंभ किस आज्ञा से होता है? कुछ को इंगित करना है, और यही doउपसर्ग करता है:

do body ; body ; body ; ...

, और अंत में, कुछ को यह इंगित करना होगा कि अंतिम शरीर को देखा गया है; एक विशेष कीवर्ड doneऐसा करता है।

इन शेल कीवर्ड को अर्धविराम अलगाव की आवश्यकता नहीं है, यहां तक ​​कि एक ही पंक्ति पर भी। उदाहरण के लिए, यदि आप कई नेस्टेड लूप बंद करते हैं, तो आपके पास बस हो सकता है done done done ...

इसके बजाय, अर्धविराम ... test ; body ... यदि वे एक ही पंक्ति में हैं। उस अर्धविराम को एक टर्मिनेटर के रूप में समझा जाता है: यह इसके साथ संबंध रखता है test। इसलिए, यदि doउनके बीच कोई कीवर्ड डाला जाता है, तो उसे अर्धविराम और के बीच जाना होगा body। यदि यह अर्धविराम के दूसरी तरफ था, तो इसे testकमांड के सिंटैक्स के अंदर गलत तरीके से एम्बेड किया जाएगा , न कि कमांड के बीच रखा जाएगा।

शेल सिंटैक्स मूल रूप से स्टीफन बॉर्न द्वारा डिजाइन किया गया था, और अल्गोल से प्रेरित है । बॉर्न, अल्गोल से इतना प्यार करता था कि उसने शेल स्रोत कोड में सी मैक्रोज़ का बहुत इस्तेमाल किया ताकि सी को अल्गोल की तरह बनाया जा सके। आप संस्करण 7 यूनिक्स से 1979-दिनांकित शेल स्रोतों को ब्राउज़ कर सकते हैं । मैक्रोज़ अंदर हैं mac.h, और उनका उपयोग सभी जगह किया जाता है। के लिए उदाहरण के ifबयान के रूप में प्रदान कर रहे हैं IF... ELSE... ELIF... FI


स्रोत कोड प्रभावशाली है।
कीथपजोलले

हाँ, यह cpp का टूर डे बल है।
चोरी करने वाला

7

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

$ while true; do ; echo foo; done
dash: 1: Syntax error: ";" unexpected
$ while ; true; do; echo; done
dash: 1: Syntax error: ";" unexpected
$ { ; echo foo; }
dash: 1: Syntax error: ";" unexpected
$ if ; true; then echo foo; fi
dash: 1: Syntax error: ";" unexpected

यहाँ तक की:

$ ; ;
dash: 1: Syntax error: ";" unexpected

इन सभी स्थानों में, एक कमांड सूची अपेक्षित है, और इसलिए एक अग्रणी ;अप्रत्याशित है।


हाँ - जिस तरह से मैंने मनमाने ढंग से एक '\ n' जोड़ा 'करो' के बाद मुझे लगता है कि 'करना' एक स्टैंड-अलोन टोकन था और न कि कुछ ऐसा जो ब्लॉक पर संचालित होता है।
कीथजोलले

यह कैसे होता है कि एक गैर-बची हुई नई पंक्ति (जो अन्यथा शेल सिंटैक्स में अर्धविराम की तरह व्यवहार करती है) की अनुमति do(और ifआदि) के बाद दी जाती है , हालांकि?
हेनिंग मैखोलम

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

3

वाक्य रचना है:

for i in [whitespace separated list of values]
do [newline separated list of commands]
done

नई सूची में से कोई भी, या तो कमांड सूची में या "करो" या "किया गया" से पहले "" को प्रतिस्थापित किया जा सकता है।

एक नई लाइन (लेकिन "नहीं";) "डू" के बाद और "इन" से पहले, केवल चीजों को अच्छे लगने के लिए अनुमति दी जाती है , लेकिन इससे वहां नई लाइन की आवश्यकता नहीं होगी


3

if अपने कीवर्ड के साथ समान है: कमांड के संक्षिप्त होने पर यह काफी पठनीय है:

if   test_commands
then true_commands
else false_commands
fi

एक बार जब मुझे एहसास हुआ कि मैं एक मनमाना में डाल दिया गया था \nके बाद doयह सब किया जाता भावना (के रूप में आपको नहीं लगता कि लंबे समय के रूप के बारे में नहीं एक मनमाना में डाल करने में सक्षम होने \nअन्य आदेशों और आर्ग के बीच)।
१३:१३ पर कीथजॉली

खैर, do, then, elseनहीं कर रहे हैं आर्ग - अगर वे थे, तो आप उन्हें पहले अर्धविराम उपयोग करने की अनुमति होगी नहीं किया। वे शेल कीवर्ड हैं (देखें type if then elif else fi)
ग्लेन जैकमैन

मुझे लगता है कि मैं उतना स्पष्ट नहीं था जितना मैं अपने उत्तर पर होना चाहता था।
कीथजॉली

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

3

संक्षिप्त उत्तर, क्योंकि यह POSIX शेल व्याकरण द्वारा निर्दिष्ट किया गया है । के बीच कुछ भी doऔर done, बयान के एक समूह माना जाता है, जबकि है ;अनुक्रमिक विभाजक है:

for_clause       : For name                                      do_group
                 | For name                       sequential_sep do_group
                 | For name linebreak in          sequential_sep do_group
                 | For name linebreak in wordlist sequential_sep do_group

do_group         : Do compound_list Done 

sequential_sep   : ';' linebreak
                 | newline_list

इसके अतिरिक्त, यदि ;मानक आवश्यक थे , तो मानक स्पष्ट रूप से राज्य होगा और sequential_sepबाद में शामिल होगा Do


1
@drewbenn आप बहुत पहले एक मतलब है? यह स्थितिगत मापदंडों के माध्यम से पुनरावृत्ति है। इसलिए यदि आपके पास एक स्क्रिप्ट है जैसे कि ./yscript.sh abc, जहाँ abc तर्क हैं, i के लिए लूप; गूंज "$ i"; किया abc के माध्यम से पाश होगा, हालांकि मुझे अभी भी लगता है कि इसे काम करने के लिए अर्धविराम की आवश्यकता होगी
Sergiy Kolodyazhnyy

ठीक है, इसलिए मेरी शंकाओं को भी दूर कर दिया गया है
सेर्गेई कोलोडियाज़नी

1

क्योंकि डू एक कीवर्ड है और जो इसका अनुसरण करता है वह अनिवार्य रूप से पैरामीटर है। बैश दुभाषिया जानता है कि अधिक अनुसरण करता है। यह 'नहीं है' के समान है;) कमांड के लिए i का अनुसरण कर रहा हूं। आप वास्तव में i के लिए के बाद एक नई लाइन जोड़ सकते हैं और बाकी को एक नई लाइन पर टाइप कर सकते हैं और यह ठीक काम करेगा।

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