विंडोज कमांड इंटरप्रेटर (CMD.EXE) स्क्रिप्ट को पार्स कैसे करता है?


142

मैं ss64.com में चला गया जो कि बैच स्क्रिप्ट लिखने के लिए अच्छी मदद प्रदान करता है कि विंडोज कमांड इंटरप्रेटर चलेगा।

हालाँकि, मैं बैच स्क्रिप्ट के व्याकरण , कैसे चीजों का विस्तार या विस्तार नहीं करता है, और चीजों से कैसे बचा जा सकता है, इसकी अच्छी व्याख्या नहीं कर पाया।

यहाँ नमूना प्रश्न हैं जिन्हें मैं हल नहीं कर पाया हूँ:

  • उद्धरण प्रणाली कैसे प्रबंधित की जाती है? मैंने एक TinyPerl स्क्रिप्ट
    ( foreach $i (@ARGV) { print '*' . $i ; }) बनाई , इसे संकलित किया और इसे इस प्रकार कहा:
    • my_script.exe "a ""b"" c" → आउटपुट है *a "b*c
    • my_script.exe """a b c""" → इसका उत्पादन करता है *"a*b*c"
  • आंतरिक echoकमांड कैसे काम करता है ? उस कमांड के अंदर क्या विस्तार किया गया है?
  • मुझे for [...] %%Iफ़ाइल स्क्रिप्ट में उपयोग क्यों करना है , लेकिन for [...] %Iइंटरैक्टिव सत्रों में?
  • भागने के पात्र क्या हैं, और किस संदर्भ में हैं? प्रतिशत चिन्ह से कैसे बचें? उदाहरण के लिए, मैं %PROCESSOR_ARCHITECTURE%शाब्दिक रूप से कैसे प्रतिध्वनित कर सकता हूं ? मैंने पाया कि echo.exe %""PROCESSOR_ARCHITECTURE%काम करता है, क्या कोई बेहतर उपाय है?
  • जोड़े कैसे %मिलते हैं? उदाहरण:
    • set b=a, echo %a %b% c%%a a c%
    • set a =b, echo %a %b% c%bb c%
  • अगर मैं इस चर को दोहरे उद्धरण चिह्नों के रूप में एक कमांड के लिए एक चर पास के रूप में कैसे सुनिश्चित करूँ?
  • setकमांड का उपयोग करते समय चर कैसे संग्रहीत किए जाते हैं ? उदाहरण के लिए, यदि मैं करता हूं set a=a" bऔर फिर echo.%a%मुझे प्राप्त होता है a" b। यदि मैं हालांकि echo.exeUnxUtils से उपयोग करता हूं, तो मुझे मिलता है a b। कैसे %a%एक अलग तरीके से फैलता है?

आपकी रोशनी के लिए धन्यवाद।


जवाबों:


200

हमने बैच स्क्रिप्ट के व्याकरण की जांच के लिए प्रयोग किए। हमने बैच और कमांड लाइन मोड के बीच अंतर की भी जांच की।

बैच लाइन पार्सर:

यहाँ बैच फ़ाइल लाइन पार्सर में चरणों का संक्षिप्त विवरण दिया गया है:

चरण 0) पढ़ें पंक्ति:

चरण 1) प्रतिशत विस्तार:

चरण 2) विशेष वर्णों की प्रक्रिया करें, टोकन करें, और कैश्ड कमांड ब्लॉक का निर्माण करें: यह एक जटिल प्रक्रिया है जो कि उद्धरण, विशेष वर्ण, टोकन परिसीमाक और कैरट पलायन जैसी चीजों से प्रभावित होती है।

चरण 3) पार्स कमांड (एस) को तब ही इको करें जब कमांड ब्लॉक के साथ शुरू नहीं हुआ था @, और पूर्ववर्ती चरण की शुरुआत में ईसीएचओ चालू था।

चरण 4) %Xचर विस्तार के लिए: केवल तभी जब कोई फ़ॉर कमांड सक्रिय हो और डीओ के बाद आदेश संसाधित किए जा रहे हों।

चरण 5) विलंबित विस्तार: विलंबित विस्तार सक्षम होने पर ही

चरण 5.3) पाइप प्रसंस्करण: केवल अगर कमांड पाइप के दोनों ओर हैं

चरण 5.5) अतिरिक्त पुनर्निर्देशन:

चरण 6) CALL प्रसंस्करण / कैरेट दोहरीकरण: केवल यदि कमांड टोकन CALL है

चरण 7) निष्पादित करें: आदेश निष्पादित किया गया है


यहां प्रत्येक चरण के लिए विवरण दिए गए हैं:

ध्यान दें कि नीचे वर्णित चरण केवल एक मॉडल है कि बैच पार्सर कैसे काम करता है। वास्तविक cmd.exe आंतरिक इन चरणों को प्रतिबिंबित नहीं कर सकता है। लेकिन यह मॉडल बैच स्क्रिप्ट के व्यवहार की भविष्यवाणी करने में प्रभावी है।

चरण 0) लाइन पढ़ें: पहले के माध्यम से इनपुट लाइन पढ़ें <LF>

  • कमांड के रूप में पार्स की जाने वाली लाइन को पढ़ते समय, <Ctrl-Z>(0x1A) को <LF>(लाइनफेड 0x0A) के रूप में पढ़ा जाता है।
  • जब GOTO या CALL एक के लिए स्कैन करते समय लाइनों को पढ़ता है: लेबल, <Ctrl-Z>को ही माना जाता है - इसे परिवर्तित नहीं किया जाता है<LF>

चरण 1) प्रतिशत विस्तार:

  • एक डबल %%एक एकल द्वारा प्रतिस्थापित किया जाता है%
  • बहस के विस्तार ( %*, %1, %2, आदि)
  • विस्तार %var%, अगर var मौजूद नहीं है, तो इसे कुछ नहीं के साथ बदलें
  • विस्तार के <LF>भीतर पहली पंक्ति में पंक्ति को काट दिया जाता है%var%
  • एक पूरी व्याख्या के लिए dbenham सेम थ्रेड: प्रतिशत चरण से इसका पहला भाग पढ़ें

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

ऐसी अवधारणाएं हैं जो इस चरण में महत्वपूर्ण हैं।

  • एक टोकन केवल पात्रों का एक स्ट्रिंग है जिसे एक इकाई के रूप में माना जाता है।
  • टोकन टोकन सीमांकक द्वारा अलग किए जाते हैं। मानक टोकन सीमांकक हैं <space> <tab> ; , = <0x0B> <0x0C>और <0xFF>
    लगातार टोकन सीमांकक को एक के रूप में माना जाता है - टोकन के बीच कोई खाली टोकन नहीं हैं
  • एक उद्धृत स्ट्रिंग के भीतर कोई टोकन सीमांकक नहीं हैं। पूरे उद्धृत स्ट्रिंग को हमेशा एकल टोकन के हिस्से के रूप में माना जाता है। एक एकल टोकन में उद्धृत स्ट्रिंग्स और अनकोट्यूट वर्णों का संयोजन हो सकता है।

इस चरण में संदर्भ के आधार पर निम्नलिखित वर्णों का विशेष अर्थ हो सकता है: <CR> ^ ( @ & | < > <LF> <space> <tab> ; , = <0x0B> <0x0C> <0xFF>

बाएं से दाएं प्रत्येक वर्ण देखें:

  • यदि <CR>तब इसे हटा दें, जैसे कि यह कभी नहीं था (अजीब पुनर्निर्देशन व्यवहार को छोड़कर )
  • यदि कोई कैरेट ( ^) है, तो अगला वर्ण बच जाता है, और भागने वाला कैरेट हटा दिया जाता है। बच गए पात्र सभी विशेष अर्थों (को छोड़कर <LF>) को खो देते हैं ।
  • यदि एक उद्धरण ( "), उद्धरण ध्वज को टॉगल करें। यदि उद्धरण ध्वज सक्रिय है, तो केवल "और <LF>विशेष हैं। अन्य सभी वर्ण अपना विशेष अर्थ खो देते हैं, जब तक कि अगली बोली बोली को बंद न कर दे। समापन उद्धरण से बचना संभव नहीं है। सभी उद्धृत वर्ण हमेशा एक ही टोकन के भीतर होते हैं।
  • <LF>हमेशा उद्धरण ध्वज को बंद कर देता है। अन्य व्यवहार संदर्भ के आधार पर भिन्न होते हैं, लेकिन उद्धरण कभी भी व्यवहार में परिवर्तन नहीं करते हैं <LF>
    • भाग निकले <LF>
      • <LF> छीन लिया गया है
      • अगला किरदार बच जाता है। यदि लाइन बफर के अंत में है, तो अगली पंक्ति को चरण 1 और 1.5 द्वारा पढ़ा और संसाधित किया जाता है और अगले चरित्र से बचने से पहले वर्तमान में जोड़ा जाता है। यदि अगला चरित्र है <LF>, तो इसे शाब्दिक माना जाता है, अर्थात यह प्रक्रिया पुनरावर्ती नहीं है।
    • <LF>कोष्ठक के भीतर नहीं बच गए
      • <LF> छीन लिया गया है और वर्तमान लाइन के पार्सिंग को समाप्त कर दिया गया है।
      • लाइन बफ़र में किसी भी शेष वर्ण को केवल अनदेखा किया जाता है।
    • के <LF>लिए एक में निहित बिना कोष्ठक ब्लॉक है
      • <LF> में परिवर्तित हो जाता है <space>
      • यदि पंक्ति बफ़र के अंत में है, तो अगली पंक्ति को वर्तमान में पढ़ा और जोड़ा जाता है।
    • <LF>एक कोष्ठक कमांड ब्लॉक के भीतर भाग गया
      • <LF>में परिवर्तित किया जाता है <LF><space>, और <space>कमांड ब्लॉक की अगली पंक्ति के हिस्से के रूप में माना जाता है।
      • यदि पंक्ति बफ़र के अंत में है, तो अगली पंक्ति को अंतरिक्ष में पढ़ा और जोड़ा जाता है।
  • यदि विशेष वर्णों में से एक & | <या >, इस बिंदु पर लाइन को विभाजित करें ताकि पाइप, कमांड कॉन्सेटेशन और पुनर्निर्देशन को संभाल सकें।
    • पाइप ( |) के मामले में , प्रत्येक पक्ष एक अलग कमांड (या कमांड ब्लॉक) है जिसे चरण 5.3 में विशेष हैंडलिंग मिलती है
    • के मामले में &, &&या ||आदेश समादेश, समवर्ती के प्रत्येक पक्ष को एक अलग कमांड के रूप में माना जाता है।
    • पुनर्निर्देशन खंड , के , या, पुनर्निर्देशन के मामले में <, अस्थायी रूप से हटा दिया गया है, और फिर वर्तमान कमांड के अंत में संलग्न है। पुनर्निर्देशन खंड में एक वैकल्पिक फ़ाइल हैंडल अंक, पुनर्निर्देशन ऑपरेटर और पुनर्निर्देशन गंतव्य टोकन होते हैं। <<>>>
      • यदि पुनर्निर्देशन ऑपरेटर से पहले का टोकन एक एकल न किया गया अंक है, तो वह अंक फ़ाइल हैंडल को पुनर्निर्देशित करने के लिए निर्दिष्ट करता है। यदि हैंडल टोकन नहीं मिला है, तो आउटपुट पुनर्निर्देशन डिफॉल्ट को 1 (स्टडआउट), और इनपुट रिडायरेक्शन डिफॉल्ट को 0 (स्टडिन) में बदल देता है।
  • यदि इस कमांड के लिए पहले टोकन (अंत तक पुनर्निर्देशन करने से पहले) के साथ शुरू होता है @, तो @इसका विशेष अर्थ है। ( @किसी अन्य संदर्भ में विशेष नहीं है)
    • विशेष @को हटा दिया जाता है।
    • यदि ECHO चालू है, तो यह कमांड, इस लाइन पर किसी भी संक्षिप्त आदेश के साथ, चरण 3 इको से बाहर रखा गया है। यदि @उद्घाटन से पहले है (, तो पूरे कोष्ठक को चरण 3 गूंज से बाहर रखा गया है।
  • प्रक्रिया कोष्ठक (कई लाइनों में यौगिक कथनों के लिए प्रदान करता है):
    • यदि पार्सर कमांड टोकन की तलाश में नहीं है, तो (विशेष नहीं है।
    • यदि पार्सर एक कमांड टोकन की तलाश में है और पाता है (, तो एक नया यौगिक स्टेटमेंट शुरू करें और कोष्ठक काउंटर को बढ़ाएं
    • यदि कोष्ठक काउंटर> 0 है तो )यौगिक विवरण को समाप्त करता है और कोष्ठक काउंटर को घटाता है।
    • यदि पंक्ति का अंत हो गया है और कोष्ठक काउंटर> 0 है, तो अगली पंक्ति को यौगिक कथन से जोड़ा जाएगा (चरण 0 से फिर से शुरू होता है)
    • यदि कोष्ठक काउंटर 0 है और पार्सर एक कमांड की तलाश में है, तो )एक REMस्टेटमेंट के समान कार्य करता है जब तक कि एक टोकन सीमांकक, विशेष चरित्र, न्यूलाइन, या एंड-ऑफ-फाइल के तुरंत बाद होता है।
      • सभी विशेष वर्ण अपना अर्थ खो देते हैं सिवाय ^(रेखा समाकलन संभव है)
      • एक बार तार्किक रेखा के अंत तक पहुंचने के बाद, पूरे "कमांड" को छोड़ दिया जाता है।
  • प्रत्येक आदेश टोकन की एक श्रृंखला में पार्स किया जाता है। पहले टोकन को हमेशा एक कमांड टोकन के रूप में माना जाता है (विशेष @को छीन लिया गया है और पुनर्निर्देशन को अंत तक ले जाया गया है)।
    • कमांड टोकन से पहले टोकन के सीमांकक छीन लिए जाते हैं
    • जब कमांड टोकन को पार्स कर रहा (है, तो मानक टोकन सीमांकक के अलावा एक कमांड टोकन सीमांकक के रूप में कार्य करता है
    • बाद के टोकन की हैंडलिंग कमांड पर निर्भर करती है।
  • अधिकांश कमांड केवल एक ही तर्क टोकन में कमांड टोकन के बाद सभी तर्कों को संक्षिप्त करते हैं। सभी तर्क टोकन परिसीमन संरक्षित हैं। तर्क विकल्प आमतौर पर चरण 7 तक पार्स नहीं किए जाते हैं।
  • तीन कमांड को विशेष हैंडलिंग मिलती है - आईएफ, फॉर, और आरईएम
    • IF को दो या तीन अलग-अलग भागों में विभाजित किया जाता है जो स्वतंत्र रूप से संसाधित होते हैं। IF कंस्ट्रक्शन में एक सिंटैक्स त्रुटि के कारण एक घातक सिंटैक्स त्रुटि होगी।
      • तुलना ऑपरेशन वास्तविक कमांड है जो चरण 7 के माध्यम से सभी तरह से बहती है
        • चरण 2 में सभी IF विकल्प पूरी तरह से पार्स किए गए हैं।
        • लगातार टोकन सीमांकक एक ही स्थान पर गिरते हैं।
        • तुलना ऑपरेटर के आधार पर, पहचाने जाने वाले एक या दो मूल्य के टोकन होंगे।
      • ट्रू कमांड ब्लॉक हालत के बाद कमांड का सेट है, और किसी भी अन्य कमांड ब्लॉक की तरह पार्स किया जाता है। यदि ईएलएसई का उपयोग किया जाना है, तो ट्रू ब्लॉक को कोष्ठक बनाना चाहिए।
      • वैकल्पिक गलत कमांड ब्लॉक ELSE के बाद कमांड का सेट है। फिर, इस कमांड ब्लॉक को सामान्य रूप से पार्स किया जाता है।
      • ट्रू और गलत कमांड ब्लॉक स्वचालित रूप से बाद के चरणों में प्रवाहित नहीं होते हैं। उनके बाद के प्रसंस्करण को चरण 7 द्वारा नियंत्रित किया जाता है।
    • डीओ के बाद दो में विभाजित है। निर्माण में एक वाक्यविन्यास त्रुटि एक घातक वाक्यविन्यास त्रुटि के परिणामस्वरूप होगी।
      • डीओ के माध्यम से भाग वास्तविक कमांड के लिए है जो चरण 7 के माध्यम से सभी तरह से बहती है
        • सभी विकल्पों के लिए चरण 2 में पूरी तरह से पार्स किया गया है।
        • कोष्ठक खंड में माना <LF>जाता है <space>। IN क्लॉज़ को पार्स किए जाने के बाद, सभी टोकन एक साथ टोकन बनाने के लिए एक साथ सम्‍मिलित किए जाते हैं।
        • डीओ के माध्यम से फ़ॉर कमांड के दौरान एक ही स्थान पर लगातार अनसुना / अनियोजित टोकन सीमांकक गिर जाते हैं।
      • डीओ के बाद का भाग एक कमांड ब्लॉक है जिसे सामान्य रूप से पार्स किया जाता है। बाद में चरण 7 में डीओ कमांड ब्लॉक के प्रसंस्करण को नियंत्रित किया जाता है।
    • चरण 2 में पाया गया रेम अन्य सभी कमांडों की तुलना में नाटकीय रूप से भिन्न माना जाता है।
      • केवल एक तर्क टोकन को पार्स किया जाता है - पार्सर पहले तर्क टोकन के बाद वर्णों की उपेक्षा करता है।
      • REM कमांड चरण 3 आउटपुट में दिखाई दे सकता है, लेकिन कमांड को कभी भी निष्पादित नहीं किया जाता है, और मूल तर्क पाठ को प्रतिध्वनित किया जाता है - बचने वाले कैरेट को हटाया नहीं जाता है, सिवाय ...
        • यदि केवल एक तर्क टोकन है जो ^लाइन को समाप्त करने वाले unescaped के साथ समाप्त होता है, तो तर्क टोकन को फेंक दिया जाता है, और बाद की रेखा को आरईएस में पार्स और जोड़ दिया जाता है। यह तब तक दोहराता है जब तक कि एक से अधिक टोकन न हों, या अंतिम वर्ण नहीं है ^
  • यदि कमांड टोकन के साथ शुरू होता है :, और यह चरण 2 का पहला दौर है (चरण 6 में कॉल के कारण पुनरारंभ नहीं है) तो
    • टोकन को आमतौर पर एक अनएक्सपेक्टेड लेबल के रूप में माना जाता है ।
      • लाइन के शेष पार्स किया गया है, तथापि ), <, >, &और |अब विशेष अर्थ नहीं होता। लाइन के पूरे शेष को लेबल "कमांड" का हिस्सा माना जाता है।
      • ^विशेष होने के लिए, जिसका अर्थ है कि लाइन निरंतरता लेबल के लिए बाद में लाइन संलग्न करने के लिए इस्तेमाल किया जा सकता जारी है।
      • एक कोष्ठबद्ध ब्लॉक के भीतर एक अस्पष्टीकृत लेबल एक घातक वाक्यविन्यास त्रुटि का परिणाम देगा जब तक कि इसे तुरंत अगली पंक्ति पर एक कमांड या निष्पादित लेबल द्वारा पालन नहीं किया जाता है ।
        • (अनएक्सपेक्टेड लेबल का अनुसरण करने वाली पहली कमांड के लिए अब कोई विशेष अर्थ नहीं है ।
      • लेबल पार्सिंग पूर्ण होने के बाद कमांड को निरस्त कर दिया जाता है। बाद के चरण लेबल के लिए जगह नहीं लेते हैं
    • तीन अपवाद हैं जो चरण 2 में पाए जाने वाले लेबल को एक निष्पादित लेबल के रूप में माना जा सकता है जो चरण 7 के माध्यम से जारी रहता है।
      • वहाँ पुनर्निर्देशन कि पछाड़ लेबल टोकन है, और वहाँ एक है |पाइप या &, &&या ||लाइन पर आदेश संयोजन।
      • पुनर्निर्देशन है जो लेबल टोकन से पहले है, और कमांड एक कोष्ठक के भीतर है।
      • लेबल टोकन एक कोष्ठक ब्लॉक के भीतर एक लाइन पर पहली कमांड है, और ऊपर की रेखा एक अनएक्सपेक्टेड लेबल के साथ समाप्त हो गई है ।
    • जब चरण 2 में एक निष्पादित लेबल खोजा जाता है, तो निम्न होता है
      • चरण 3 में लेबल, इसके तर्क और इसके पुनर्निर्देशन को किसी भी प्रतिध्वनि आउटपुट से बाहर रखा गया है
      • लाइन पर किसी भी बाद के समाप्‍त कमांड को पूरी तरह से पार्स और निष्पादित किया जाता है।
    • के बारे में अधिक जानकारी के लिए निष्पादित लेबल बनाम बेरोज़गार लेबल , देख https://www.dostips.com/forum/viewtopic.php?f=3&t=3803&p=55405#p55405

चरण 3) पार्स कमांड (एस) को तब ही इको करें जब कमांड ब्लॉक के साथ शुरू नहीं हुआ था @, और पूर्ववर्ती चरण की शुरुआत में ईसीएचओ चालू था।

चरण 4) %Xचर विस्तार के लिए: केवल तभी जब कोई फ़ॉर कमांड सक्रिय हो और डीओ के बाद आदेश संसाधित किए जा रहे हों।

  • इस बिंदु पर, बैच प्रसंस्करण का चरण 1 पहले से ही एक परिवर्तनशील चर को जैसे %%Xमें बदल देगा %X। चरण 1 के लिए कमांड लाइन के अलग-अलग प्रतिशत विस्तार नियम हैं। यही कारण है कि कमांड लाइन का उपयोग करते हैं, %Xलेकिन बैच फाइलें %%Xचर के लिए उपयोग करती हैं।
  • चर नामों के लिए मामला संवेदनशील है, लेकिन ~modifiersमामला संवेदनशील नहीं हैं।
  • ~modifiersचर नामों पर पूर्वता लें। यदि एक वर्ण निम्नलिखित में ~से एक संशोधक और चर नाम के लिए मान्य है, और इसके बाद का वर्ण मौजूद है जो चर नाम के लिए एक सक्रिय है, तो चरित्र को एक संशोधक के रूप में व्याख्या की जाती है।
  • परिवर्तनशील नाम वैश्विक हैं, लेकिन केवल डीओ क्लॉज के संदर्भ में हैं। अगर एक रूट को FOR DO क्लॉज़ के भीतर से कॉल किया जाता है, तो CALLed रूटीन में फ़ोर वेरिएबल्स का विस्तार नहीं किया जाता है। लेकिन अगर दिनचर्या अपनी ही के लिए आदेश है, तो सभी वर्तमान में चर के लिए परिभाषित भीतरी डीओ आदेशों के लिए उपलब्ध हैं।
  • चर नामों के लिए नेस्टेड फ़ॉर्म्स के भीतर पुन: उपयोग किया जा सकता है। आंतरिक मूल्य के लिए पूर्वता है, लेकिन एक बार जब INNER बंद हो जाता है, तो बाहरी मूल्य के लिए बहाल हो जाता है।
  • यदि ECHO इस चरण के प्रारंभ में चालू था, तो चरण 3) के लिए पार्स किए गए DO आदेशों को दर्शाने के बाद दोहराया जाता है।

---- इस बिंदु से, चरण 2 में पहचाने गए प्रत्येक कमांड को अलग से संसाधित किया जाता है।
---- चरण 5 से 7 के माध्यम से अगले पर जाने से पहले एक कमांड के लिए पूरा किया जाता है।

चरण 5) विलंबित विस्तार: केवल यदि विलंबित विस्तार चालू है, तो कमांड एक पाइप के दोनों ओर एक कोष्ठक खंड में नहीं है , और कमांड "नग्न" बैच स्क्रिप्ट नहीं है (बिना कोष्ठक के स्क्रिप्ट नाम, CALL, कमांड संघटन, या पाइप)।

  • एक कमांड के लिए प्रत्येक टोकन को स्वतंत्र रूप से विलंबित विस्तार के लिए पार्स किया गया है।
    • अधिकांश कमांड दो या दो से अधिक टोकन पार्स करते हैं - कमांड टोकन, तर्क टोकन और प्रत्येक पुनर्निर्देशन गंतव्य टोकन।
    • आदेश के लिए केवल खंड टोकन में पार्स करता है।
    • आईएफ कमांड तुलनात्मक ऑपरेटर के आधार पर तुलनात्मक मूल्यों को केवल एक या दो के आधार पर पार्स करता है।
  • पार्स किए गए प्रत्येक टोकन के लिए, पहले जांचें कि क्या उसमें कोई है !। यदि नहीं, तो टोकन को पार्स नहीं किया गया है - ^पात्रों के लिए महत्वपूर्ण है । यदि टोकन शामिल है !, तो प्रत्येक वर्ण को बाएं से दाएं स्कैन करें:
    • यदि यह एक कैरेट है ( ^) अगले चरित्र का कोई विशेष अर्थ नहीं है, तो कैरेट को हटा दिया जाता है
    • यदि यह एक विस्मयादिबोधक चिह्न है, तो अगले विस्मयादिबोधक चिह्न की खोज करें (देखभाल अब नहीं देखी गई है), चर के मूल्य तक विस्तृत करें।
      • लगातार उद्घाटन !एक एकल में ढह जाता है!
      • किसी भी शेष अनपढ़ !को हटा दिया जाता है
    • इस स्तर पर वार्स विस्तार "सुरक्षित", अब और (यहां तक कि है, क्योंकि विशेष वर्ण का पता नहीं चलने <CR>या <LF>)
    • अधिक संपूर्ण स्पष्टीकरण के लिए, इस के 2 आधे भाग को डेंभम उसी थ्रेड से पढ़ें - विस्मयादिबोधक बिंदु चरण

चरण 5.3) पाइप प्रसंस्करण: केवल तभी जब पाइप के दोनों ओर कमांड होते हैं पाइप के
प्रत्येक पक्ष को स्वतंत्र रूप से और अतुल्यकालिक रूप से संसाधित किया जाता है।

  • यदि कमांड cmd.exe के लिए आंतरिक है, या यह एक बैच फ़ाइल है, या यदि यह एक कोष्ठक कमांड ब्लॉक है, तो इसे नए cmd.exe थ्रेड के माध्यम से निष्पादित किया %comspec% /S /D /c" commandBlock"जाता है, इसलिए कमांड ब्लॉक को एक चरण पुनरारंभ होता है, लेकिन इस बार कमांड लाइन मोड में।
    • यदि एक कोष्ठक कमांड कमांड ब्लॉक करता है, तो <LF>पहले और बाद में एक कमांड के साथ सभी को परिवर्तित किया जाता है <space>&। अन्य <LF>छीन लिए गए हैं।
  • यह पाइप कमांड के लिए प्रोसेसिंग का अंत है।
  • देखें कि कोड के पाइप ब्लॉक के अंदर विस्तार में देरी क्यों विफल हो जाती है? पाइप पार्सिंग और प्रसंस्करण के बारे में अधिक जानकारी के लिए

चरण 5.5) निष्पादित पुनर्निर्देशन: चरण 2 में खोजे गए किसी भी पुनर्निर्देशन को अब निष्पादित किया गया है।

चरण 6) कॉल प्रोसेसिंग / कैरेट दोहरीकरण: केवल यदि कमांड टोकन कॉल है, या यदि पहले होने वाला मानक टोकन सीमांकक से पहले पाठ कॉल है। यदि CALL को एक बड़े कमांड टोकन से पार्स किया जाता है, तो अप्रयुक्त भाग को आगे बढ़ने से पहले टोकन के तर्कों के लिए तैयार किया जाता है।

  • एक निर्विवाद के लिए तर्क टोकन को स्कैन करें /?। यदि टोकन के भीतर कहीं भी पाया जाता है, तो चरण 6 को निरस्त करें और चरण 7 पर जाएं, जहां कॉल के लिए हेल्प मुद्रित की जाएगी।
  • पहले निकालें CALL, इसलिए कई कॉल को स्टैक किया जा सकता है
  • डबल सभी देखभाल
  • चरण 1, 1.5 और 2 को फिर से शुरू करें, लेकिन चरण 3 में जारी न रखें
    • जब तक वे उद्धृत नहीं किए जाते हैं तब तक किसी भी दोहरी देखभाल को एक कैरेट में वापस घटाया जाता है। लेकिन दुर्भाग्य से, उद्धृत देखभाल दोगुनी है।
    • चरण 1 थोड़ा बदलता है
      • चरण 1.2 या 1.3 में विस्तार त्रुटियां कॉल को रोकती हैं, लेकिन त्रुटि घातक नहीं है - बैच प्रसंस्करण जारी है।
    • चरण 2 कार्यों को थोड़ा बदल दिया जाता है
      • कोई भी नया दिखने वाला, बिना लिखा हुआ पुनर्निर्देशन जो चरण 2 के पहले दौर में नहीं पाया गया था, का पता लगाया गया है, लेकिन इसे हटा दिया गया है (फ़ाइल नाम सहित) वास्तव में पुनर्निर्देशन किए बिना
      • किसी भी नव दिखाई देने वाले, पंक्ति के अंत में बिना सहेजे हुए लापरवाह लाइन निरंतरता के प्रदर्शन के बिना हटा दिया जाता है
      • CALL को त्रुटि के बिना निरस्त किया जाता है यदि निम्न में से किसी का पता लगाया जाता है
        • नवनियुक्त दिखाई दे रहा है, अधूरा &या|
        • परिणामी कमांड टोकन की शुरुआत बिना पढ़े, बिना पढ़े के साथ होती है (
        • हटाए गए CALL के साथ बहुत पहले टोकन शुरू हुआ @
      • यदि परिणामी कमांड एक उचित रूप से मान्य IF या FOR है, तो निष्पादन बाद में एक त्रुटि के साथ विफल होगा जो यह बताता है कि IFया FORआंतरिक या बाहरी कमांड के रूप में मान्यता प्राप्त नहीं है।
      • बेशक CALL चरण 2 के इस 2 राउंड में निरस्त नहीं होता है यदि परिणामी कमांड टोकन एक लेबल शुरुआत है :
  • यदि परिणामी कमांड टोकन CALL है, तो चरण 6 को फिर से शुरू करें (तब तक दोहराएं जब तक कोई CALL नहीं)
  • यदि परिणामी कमांड टोकन एक बैच स्क्रिप्ट या a: लेबल है, तो CALL का निष्पादन पूरी तरह से चरण 6 के शेष भाग द्वारा नियंत्रित किया जाता है।
    • कॉल स्टैक पर वर्तमान बैच स्क्रिप्ट फ़ाइल स्थिति को पुश करें ताकि CALL पूरा होने पर निष्पादन सही स्थिति से फिर से शुरू हो सके।
    • सभी परिणामी टोकन का उपयोग करके CALL के लिए% 0,% 1,% 2, ...% N और% * तर्क टोकन सेट करें
    • यदि कमांड टोकन एक लेबल है जो इसके साथ शुरू होता है :, तो
      • चरण 5 को पुनरारंभ करें। यह प्रभावित कर सकता है क्या: लेबल को कॉल किया गया है। लेकिन चूँकि% 0 आदि टोकन पहले ही सेटअप हो चुके हैं, इसलिए यह उन तर्कों को नहीं बदलेगा, जिन्हें CALLed रूटीन में पास किया गया है।
      • GOTO लेबल को उप-आरंभ की शुरुआत में फ़ाइल पॉइंटर की स्थिति के लिए लेबल करें (किसी भी अन्य टोकन की अनदेखी करें: लेबल का पालन कर सकते हैं) GOTO कैसे काम करता है इसके नियमों के लिए चरण 7 देखें।
    • निर्दिष्ट बैच स्क्रिप्ट के लिए स्थानांतरण हस्तांतरण नियंत्रण।
    • CALLed का निष्पादन: लेबल या स्क्रिप्ट तब तक जारी रहता है जब तक कि EXIT / B या एंड-ऑफ-फ़ाइल नहीं पहुंच जाता है, जिस बिंदु पर CALL स्टैक पॉप होता है और सहेजे गए फ़ाइल स्थिति से निष्पादन फिर से शुरू होता है।
      चरण 7 को स्क्रिप्टेड स्क्रिप्ट या लेबल के लिए निष्पादित नहीं किया गया है।
  • चरण 6 का परिणाम निष्पादन के लिए चरण 7 में आता है।

चरण 7) निष्पादित करें: आदेश निष्पादित किया गया है

  • 7.1 - आंतरिक कमांड को निष्पादित करें - यदि कमांड टोकन उद्धृत किया गया है, तो इस चरण को छोड़ दें। अन्यथा, एक आंतरिक कमांड को पार्स करने और निष्पादित करने का प्रयास करें।
    • निम्न परीक्षण यह निर्धारित करने के लिए किए जाते हैं कि क्या एक निर्विवाद कमांड टोकन एक आंतरिक कमांड का प्रतिनिधित्व करता है:
      • यदि कमांड टोकन वास्तव में आंतरिक कमांड से मेल खाता है, तो इसे निष्पादित करें।
      • पहले की घटना होने से पहले कमांड का टोकन टूट जाता है + / [ ] <space> <tab> , ;या =
        यदि पूर्ववर्ती पाठ एक आंतरिक कमांड है, तो उस कमांड को याद रखें
        • यदि कमांड लाइन मोड में, या यदि कमांड एक कोष्ठककृत ब्लॉक से है, यदि सही या गलत कमांड ब्लॉक, डीओ कमांड ब्लॉक के लिए, या कमांड कॉन्टेनेशन के साथ शामिल है, तो आंतरिक कमांड निष्पादित करें
        • एल्स (बैच मोड में एक स्टैंड-अलोन कमांड होना चाहिए) एक .COM, .EXE, .BAT, या .CMD फ़ाइल के लिए वर्तमान फ़ोल्डर और PATH को स्कैन करता है जिसका आधार नाम मूल कमांड टोकन से मेल खाता है।
          • यदि पहली मिलान फ़ाइल एक .BAT या .CMD है, तो गोटो 7.3.exec और उस स्क्रिप्ट को निष्पादित करें
          • एल्स (मिलान नहीं मिला या पहला मैच .EXE या .COM) याद किए गए आंतरिक कमांड को निष्पादित करता है
      • पहले की घटना से पहले कमांड टोकन को तोड़ देता है . \या :
        यदि पूर्ववर्ती पाठ एक आंतरिक कमांड नहीं है, तो गोटो 7.2
        पूर्ववर्ती पाठ एक आंतरिक आदेश हो सकता है। इस कमांड को याद रखें।
      • की पहली घटना से पहले कमांड टोकन को तोड़ दें + / [ ] <space> <tab> , ;या =
        यदि पूर्ववर्ती पाठ एक मौजूदा फ़ाइल के लिए एक पथ है, तो गोटो 7.2
        एल्स याद किए गए आंतरिक कमांड को निष्पादित करता है।
    • यदि एक आंतरिक कमांड को एक बड़े कमांड टोकन से पार्स किया जाता है, तो कमांड टोकन का अप्रयुक्त भाग तर्क सूची में शामिल होता है
    • सिर्फ इसलिए कि एक कमांड टोकन को आंतरिक कमांड के रूप में पार्स किया जाता है, इसका मतलब यह नहीं है कि यह सफलतापूर्वक निष्पादित होगा। प्रत्येक आंतरिक कमांड के अपने नियम होते हैं कि कैसे तर्कों और विकल्पों को पार्स किया जाता है, और किस सिंटैक्स की अनुमति है।
    • यदि सभी आंतरिक आदेशों /?का पता लगाने के बजाय उनके कार्य को करने में मदद करेगा । अधिकांश /?यह तर्क में कहीं भी प्रकट होता है, तो पहचानें । लेकिन ECHO और SET जैसे कुछ कमांड केवल प्रिंट मदद करते हैं यदि पहला तर्क टोकन शुरू होता है /?
    • सेट के कुछ दिलचस्प शब्दार्थ हैं:
      • यदि SET कमांड में चर नाम और एक्सटेंशन सक्षम होने से पहले एक उद्धरण है
        set "name=content" ignored -> मान = content
        तो पहले बराबर चिह्न और अंतिम उद्धरण के बीच के पाठ का उपयोग सामग्री के रूप में किया जाता है (पहले बराबर और अंतिम उद्धरण को बाहर रखा गया है)। अंतिम उद्धरण के बाद पाठ को अनदेखा किया जाता है। यदि समान चिह्न के बाद कोई उद्धरण नहीं है, तो बाकी पंक्ति सामग्री के रूप में उपयोग की जाती है।
      • यदि SET कमांड में नाम से पहले कोई उद्धरण नहीं है
        set name="content" not ignored -> मान = "content" not ignored
        तो समतुल्य के बाद की शेष रेखा सामग्री के रूप में उपयोग की जाती है, जिसमें कोई भी और सभी उद्धरण शामिल हो सकते हैं।
    • एक IF तुलना का मूल्यांकन किया जाता है, और यह इस बात पर निर्भर करता है कि स्थिति सही है या गलत, चरण 5 के साथ शुरू होने वाले उपयुक्त पहले से ही निर्भर आश्रित कमांड ब्लॉक को संसाधित किया जाता है।
    • एक आदेश का खंड उचित रूप से iterated है।
      • यदि यह एक FOR / F है जो कमांड ब्लॉक के आउटपुट को पुनरावृत्त करता है, तो:
        • IN क्लॉज को CMD / C के माध्यम से एक नई cmd.exe प्रक्रिया में निष्पादित किया जाता है।
        • कमांड ब्लॉक को दूसरी बार पूरी पार्सिंग प्रक्रिया से गुजरना होगा, लेकिन इस बार कमांड लाइन के संदर्भ में
        • ECHO चालू हो जाएगा, और विलंबित विस्तार आमतौर पर अक्षम होना शुरू हो जाएगा (रजिस्ट्री सेटिंग पर निर्भर)
        • एक बार चाइल्ड cmd.exe प्रक्रिया समाप्त होने पर IN क्लॉज कमांड ब्लॉक द्वारा किए गए सभी पर्यावरण परिवर्तन समाप्त हो जाएंगे
      • प्रत्येक पुनरावृत्ति के लिए:
        • परिवर्तनशील मानों के लिए परिभाषित किया गया है
        • चरण 4 के साथ शुरू होने वाले पहले से ही पार्स डीओ कमांड ब्लॉक को संसाधित किया जाता है।
    • GOTO: लेबल का पता लगाने के लिए निम्न तर्क का उपयोग करता है
      • लेबल को पहले तर्क टोकन से पार्स किया गया है
      • लेबल की अगली घटना के लिए स्क्रिप्ट स्कैन की जाती है
        • स्कैन वर्तमान फ़ाइल स्थिति से शुरू होता है
        • यदि फ़ाइल का अंत पहुँच जाता है, तो स्कैन फ़ाइल की शुरुआत में वापस लूप करता है और मूल शुरुआती बिंदु पर जारी रहता है।
      • स्कैन उस लेबल की पहली घटना पर रुक जाता है, जिसे वह पाता है, और फ़ाइल पॉइंटर लेबल के तुरंत बाद लाइन पर सेट हो जाता है। स्क्रिप्ट का निष्पादन उस बिंदु से शुरू होता है। ध्यान दें कि एक सफल असली GOTO कोड के किसी भी ब्लॉक किए गए ब्लॉक को तुरंत लूप सहित निरस्त कर देगा।
      • यदि लेबल नहीं मिला है, या लेबल टोकन गायब है, तो GOTO विफल रहता है, एक त्रुटि संदेश मुद्रित होता है, और कॉल स्टैक पॉप होता है। यह प्रभावी रूप से एक EXIT / B के रूप में कार्य करता है, GOTO का पालन करने वाले वर्तमान कमांड ब्लॉक में किसी भी पहले से मौजूद कमांड को अभी भी निष्पादित किया जाता है, लेकिन CALLer के संदर्भ में (संदर्भ जो EXIT / B के बाद मौजूद है)
      • पार्सिंग लेबल के लिए उपयोग किए जाने वाले नियमों के अधिक सटीक विवरण के लिए https://www.dostips.com/forum/viewtopic.php?f=3&t=3803 देखें ।
    • RENAME और COPY दोनों वाइल्डकार्ड को स्रोत और लक्ष्य पथ के लिए स्वीकार करते हैं। लेकिन Microsoft एक भयानक काम का दस्तावेजीकरण करता है कि वाइल्डकार्ड कैसे काम करते हैं, खासकर लक्ष्य पथ के लिए। वाइल्डकार्ड नियमों का एक उपयोगी सेट पाया जा सकता है कि विंडोज रेनैम कमांड वाइल्डकार्ड की व्याख्या कैसे करता है?
  • 7.2 - परिमाण मात्रा में परिवर्तन - यदि कमांड टोकन एक उद्धरण के साथ शुरू नहीं होता है, तो ठीक दो वर्ण लंबा है, और दूसरा वर्ण बृहदान्त्र है, फिर मात्रा बदलें
    • सभी तर्क टोकन की अनदेखी की जाती है
    • यदि पहले वर्ण द्वारा निर्दिष्ट वॉल्यूम नहीं मिल सकता है, तो एक त्रुटि के साथ गर्भपात करें
    • एक कमांड के टोकन ::हमेशा एक त्रुटि में परिणाम जब तक SUBST के लिए एक मात्रा को परिभाषित करने के लिए किया जाता है जाएगा ::
      तो SUBST के लिए एक मात्रा को परिभाषित करने के लिए किया जाता है ::, तो मात्रा बदल जाएगा, यह एक लेबल के रूप में नहीं माना जाएगा।
  • .३ - बाहरी आदेश का पालन करें - आदेश को बाहरी आदेश के रूप में मानने का प्रयास करें।
    • कमांड लाइन मोड और आदेश में उद्धृत नहीं किया गया है और एक मात्रा विनिर्देश, सफेद-अंतरिक्ष से शुरू नहीं होता, ,, ;, =या +तो आदेश की पहली आवृत्ति पर टोकन तोड़ने <space> , ;या =और टोकन (रों) तर्क को शेष पहले जोड़ें।
    • यदि कमांड टोकन का दूसरा वर्ण एक बृहदान्त्र है, तो सत्यापित करें कि 1 वर्ण द्वारा निर्दिष्ट वॉल्यूम पाया जा सकता है।
      यदि वॉल्यूम नहीं मिल सकता है, तो एक त्रुटि के साथ गर्भपात करें।
    • यदि बैच मोड और कमांड टोकन के साथ शुरू होता है :, तो गोटो 7.4
      नोट करें कि यदि लेबल टोकन के साथ शुरू होता है ::, तो यह नहीं पहुंचेगा क्योंकि पूर्ववर्ती चरण एक त्रुटि के साथ समाप्त हो जाएगा जब तक कि SUBST का उपयोग किसी वॉल्यूम को परिभाषित करने के लिए नहीं किया जाता है ::
    • निष्पादित करने के लिए बाहरी कमांड को पहचानें।
      • यह एक जटिल प्रक्रिया है जिसमें वर्तमान मात्रा, वर्तमान निर्देशिका, पथ चर, पथ चर और फ़ाइल संघ शामिल हो सकते हैं।
      • यदि एक वैध बाहरी कमांड की पहचान नहीं की जा सकती है, तो एक त्रुटि के साथ गर्भपात करें।
    • यदि कमांड लाइन मोड में और कमांड टोकन के साथ शुरू होता है :, तो गोटो 7.4
      ध्यान दें कि यह शायद ही कभी पहुंचता है क्योंकि पूर्ववर्ती कदम एक त्रुटि के साथ समाप्त हो जाएगा जब तक कि कमांड टोकन शुरू नहीं होता है ::, और SUBST का उपयोग किसी वॉल्यूम को परिभाषित करने के लिए किया जाता है ::, और संपूर्ण कमांड टोकन बाहरी कमांड का एक वैध मार्ग है।
    • 7.3.exec - बाहरी कमांड निष्पादित करें।
  • .४ - एक लेबल को अनदेखा करें - कमांड टोकन शुरू होने पर कमांड और उसके सभी तर्कों को अनदेखा करें :
    7.2 और 7.3 में नियम एक लेबल को इस बिंदु तक पहुंचने से रोक सकते हैं।

कमांड लाइन पार्सर:

इसके अलावा बैचलाइन-पार्सर की तरह काम करता है:

चरण 1) प्रतिशत विस्तार:

  • नहीं %*, %1आदि तर्क विस्तार
  • यदि var अपरिभाषित है, तो %var%अपरिवर्तित छोड़ दिया जाता है।
  • की कोई विशेष हैंडलिंग नहीं %%। यदि var = सामग्री है, तो %%var%%विस्तार करता है %content%

चरण 3) पार्स की गई कमांड को प्रतिध्वनित करें

  • यह चरण 2 के बाद नहीं किया जाता है। यह केवल FOR DO कमांड ब्लॉक के लिए चरण 4 के बाद किया जाता है।

चरण 5) विलंबित विस्तार: केवल तभी विलंबित विस्तार सक्षम है

  • यदि var अपरिभाषित है, तो !var!अपरिवर्तित छोड़ दिया जाता है।

चरण 7) एक्सक्यूट कमांड

  • CALL या GOTO का प्रयास: एक त्रुटि में लेबल परिणाम।
  • जैसा कि पहले ही चरण 7 में प्रलेखित है, एक निष्पादित लेबल के परिणामस्वरूप विभिन्न परिदृश्यों में त्रुटि हो सकती है।
    • बैच निष्पादित लेबल केवल एक त्रुटि का कारण बन सकते हैं यदि वे शुरू करते हैं ::
    • कमांड लाइन निष्पादित लेबल लगभग हमेशा एक त्रुटि का परिणाम है

पूर्णांक मानों की पार्सिंग

कई अलग-अलग संदर्भ हैं जहां cmd.exe तार से पूर्णांक मानों को पार्स करता है, और नियम असंगत हैं:

  • SET /A
  • IF
  • %var:~n,m% (चर विकल्प का विस्तार)
  • FOR /F "TOKENS=n"
  • FOR /F "SKIP=n"
  • FOR /L %%A in (n1 n2 n3)
  • EXIT [/B] n

CMD.EXE पार्स नंबरों की संख्या के लिए इन नियमों के विवरण नियमों पर पाए जा सकते हैं


Cmd.exe पार्सिंग नियमों में सुधार करने के इच्छुक किसी भी व्यक्ति के लिए, DosTips फ़ोरम पर एक चर्चा का विषय है जहाँ मुद्दों की सूचना दी जा सकती है और सुझाव दिए जा सकते हैं।

आशा है कि यह
जन एरिक (जेईबी) - मूल लेखक और चरणों के
खोजकर्ता डेव बेन्हम (debham) में मदद करता है - बहुत अधिक सामग्री और संपादन


4
हैलो जेब, आपकी अंतर्दृष्टि के लिए धन्यवाद ... यह समझना मुश्किल हो सकता है, लेकिन मैं इसके माध्यम से सोचने की कोशिश करूंगा! आपको लगता है कि आपने बहुत परीक्षण किए हैं! अनुवाद करने के लिए धन्यवाद ( admin.de/… )
Benoit

2
चरण 5) - %% एक पहले से ही चरण 1 में% के लिए बदल दिया गया है, इसलिए लूप विस्तार वास्तव में% a का विस्तार करता है। इसके अलावा, मैंने नीचे दिए गए एक उत्तर में बैच चरण 1 का अधिक विस्तृत विवरण जोड़ा (मेरे पास विशेषाधिकार संपादित नहीं है)
dbenham

3
जेब - शायद चरण 0 को स्थानांतरित किया जा सकता है और चरण 6 के साथ जोड़ा जा सकता है? यह मेरे लिए अधिक समझ में आता है, या कोई कारण है कि वे इस तरह अलग क्यों हैं?
डेबनहम

1
@aschipfl - मैंने उस अनुभाग को अपडेट किया। )वास्तव में लगभग एक जैसे समारोह करता है REMजब कोष्टक काउंटर 0. दोनों कमांड लाइन से इनमें से कोशिश है आदेश: ) Ignore this, औरecho OK & ) Ignore this
dbenham

1
@aschipfl हाँ यह सही है, इसके अलावा आप कभी-कभी "var =% expr%" सेट करते हैं! 'अंतिम विस्मयादिबोधक चिह्न हटा दिया जाएगा, लेकिन चरण 5
जेब

62

जब एक कमांड विंडो से एक कमांड का आह्वान किया जाता है, तो कमांड लाइन के तर्क का टोकन cmd.exe(उर्फ "शेल") द्वारा नहीं किया जाता है । अधिकांश अक्सर टोकन नवगठित प्रक्रियाओं 'C / C ++ रनटाइम द्वारा किया जाता है, लेकिन यह आवश्यक नहीं है - उदाहरण के लिए, यदि नई प्रक्रिया C / C ++ में नहीं लिखी गई थी, या यदि नई प्रक्रिया को अनदेखा करना argvऔर प्रक्रिया करना चुनता है स्वयं के लिए कच्ची कमांडलाइन (जैसे GetCommandLine के साथ ))। ओएस के स्तर पर, विंडोज नई प्रक्रियाओं के लिए एक स्ट्रिंग के रूप में अनधिकृत रूप से गुजरती है। यह अधिकांश * निक्स के गोले के विपरीत है, जहां शेल नवगठित प्रक्रिया को पारित करने से पहले एक सुसंगत, पूर्वानुमानित तरीके से तर्कों को मिटा देता है। इसका मतलब यह है कि आप विंडोज पर अलग-अलग कार्यक्रमों में बेतहाशा तर्क वितर्क व्यवहार का अनुभव कर सकते हैं, क्योंकि व्यक्तिगत कार्यक्रम अक्सर तर्क टोकन को अपने हाथों में लेते हैं।

यदि यह अराजकता की तरह लगता है, तो यह एक तरह का है। तथापि, Windows कार्यक्रमों की एक बड़ी संख्या के बाद से कर माइक्रोसॉफ्ट C / C ++ रनटाइम के उपयोग argv, यह समझना आम तौर पर उपयोगी हो सकता है कि कैसे MSVCRT tokenizes तर्क। यहाँ एक अंश है:

  • तर्क को सफेद स्थान द्वारा सीमांकित किया जाता है, जो या तो एक स्थान या एक टैब है।
  • दोहरे उद्धरण चिह्नों से घिरे एक स्ट्रिंग को एकल तर्क के रूप में व्याख्या की जाती है, भले ही भीतर निहित सफेद स्थान की परवाह किए बिना। एक उद्धृत स्ट्रिंग को एक तर्क में एम्बेड किया जा सकता है। ध्यान दें कि कैरेट (^) को भागने के पात्र या सीमांकक के रूप में मान्यता प्राप्त नहीं है।
  • बैकस्लैश, \ "से पहले दोहरा उद्धरण चिह्न, शाब्दिक दोहरे उद्धरण चिह्न (") के रूप में व्याख्या किया गया है।
  • बैकस्लैश की शाब्दिक व्याख्या की जाती है, जब तक कि वे तुरंत दोहरे उद्धरण चिह्न से पहले न हों।
  • यदि बैकस्लैश की एक समान संख्या का दोहरे उद्धरण चिह्न के बाद किया जाता है, तो बैकस्लैश (\) की प्रत्येक जोड़ी के लिए एक बैकस्लैश () को arvv एरे में रखा जाता है, और डबल कोटेशन मार्क (") को एक स्ट्रिंग सीमांकक के रूप में व्याख्या किया जाता है।
  • यदि बैकस्लैश की एक विषम संख्या दोहरे उद्धरण चिह्न के बाद होती है, तो बैकस्लैश (\) की प्रत्येक जोड़ी के लिए एक बैकस्लैश () को argv एरे में रखा जाता है और डबल कोटेशन मार्क को शेष बैकलैश द्वारा एक एस्केप सीक्वेंस के रूप में समझा जाता है, जिससे Argv में रखा जाने वाला एक शाब्दिक दोहरा उद्धरण चिह्न (")।

Microsoft "बैच भाषा" ( .bat) इस अराजक वातावरण के लिए कोई अपवाद नहीं है, और इसने टोकनकरण और भागने के लिए अपने स्वयं के अनूठे नियमों को विकसित किया है। यह भी लगता है कि cmd.exe कमांड प्रॉम्प्ट नए निष्पादन प्रक्रिया को तर्क पास करने से पहले कमांड लाइन तर्क (ज्यादातर चर प्रतिस्थापन और भागने के लिए) के कुछ प्रीप्रोसेसिंग करता है। आप इस पृष्ठ पर jeb और dbenham द्वारा उत्कृष्ट उत्तरों में बचने वाली बैच भाषा और cmd के निम्न-स्तरीय विवरणों के बारे में अधिक पढ़ सकते हैं।


चलो C में एक साधारण कमांड लाइन उपयोगिता बनाते हैं और देखते हैं कि यह आपके परीक्षण मामलों के बारे में क्या कहता है:

int main(int argc, char* argv[]) {
    int i;
    for (i = 0; i < argc; i++) {
        printf("argv[%d][%s]\n", i, argv[i]);
    }
    return 0;
}

(नोट्स: argv [0] हमेशा निष्पादन योग्य का नाम है, और संक्षिप्तता के लिए नीचे छोड़ा गया है। Windows XP SP3 पर परीक्षण किया गया है। विजुअल स्टूडियो 2005 के साथ संकलित है।)

> test.exe "a ""b"" c"
argv[1][a "b" c]

> test.exe """a b c"""
argv[1]["a b c"]

> test.exe "a"" b c
argv[1][a" b c]

और मेरे खुद के कुछ परीक्षण:

> test.exe a "b" c
argv[1][a]
argv[2][b]
argv[3][c]

> test.exe a "b c" "d e
argv[1][a]
argv[2][b c]
argv[3][d e]

> test.exe a \"b\" c
argv[1][a]
argv[2]["b"]
argv[3][c]

आपके उत्तर के लिए धन्यवाद। यह मुझे यह देखने के लिए और भी अधिक याद दिलाता है कि टाइनीपेरल आपके प्रोग्राम को आउटपुट नहीं देता है, और मुझे यह समझने में कठिनाई होती है कि पोस्ट-प्रोसेसिंग कैसे [a "b" c]हो सकता है [a "b] [c]
बेनोइट

अब जब मैं इसके बारे में सोचता हूं, तो कमांड लाइन का यह टोकन पूरी तरह से सी रनटाइम द्वारा किया जाता है। एक निष्पादन योग्य ऐसा लिखा जा सकता है कि यह सी रनटाइम का उपयोग भी नहीं करता है, जिस स्थिति में मुझे लगता है कि इसे कमांड लाइन वर्बेटिम से निपटना होगा, और इसके स्वयं के टोकन करने के लिए जिम्मेदार होगा (यदि यह चाहता था) या यहां तक ​​कि। यदि आपका एप्लिकेशन C रनटाइम का उपयोग करता है, तो आप argc और argv को नजरअंदाज करना चुन सकते हैं और केवल Read32 के माध्यम से कच्ची कमांड लाइन प्राप्त कर सकते हैं GetCommandLine। शायद TinyPerl argv को नजरअंदाज कर रहा है और बस अपने नियम से कच्ची कमांड लाइन को टोकन दे रहा है।
माइक क्लार्क

4
"याद रखें कि Win32 के दृष्टिकोण से, कमांड लाइन सिर्फ एक स्ट्रिंग है जिसे नई प्रक्रिया के पता स्थान में कॉपी किया जाता है। कैसे लॉन्च प्रक्रिया और नई प्रक्रिया इस स्ट्रिंग की व्याख्या करती है, यह नियमों द्वारा नहीं बल्कि सम्मेलन द्वारा नियंत्रित किया जाता है।" -Raymond Chen blogs.msdn.com/b/oldnewthing/archive/2009/11/25/9928372.aspx
माइक क्लार्क

2
वास्तव में अच्छा जवाब देने के लिए धन्यवाद। यह मेरी राय में बहुत कुछ समझाता है। और यह भी बताता है कि क्यों मुझे कभी-कभी लगता है कि विंडोज के साथ काम करने के लिए वास्तव में भद्दा है ...
बेनोइट

मैं Win32 C ++ प्रोग्राम के लिए कमांडलाइन से argv में परिवर्तन के दौरान बैकस्लैश और उद्धरण के बारे में यह पाया । बैकस्लैश की गिनती को केवल दो से विभाजित किया जाता है जब अंतिम बैकस्लैश के बाद एक dblquote होता है, और dblquote एक स्ट्रिंग को समाप्त करता है जब बैकस्लैश की एक समान संख्या होती है।
बेनोइट

47

प्रतिशत विस्तार नियम

जेब के उत्तर में चरण 1 का विस्तृत विवरण दिया गया है (बैच मोड और कमांड लाइन मोड दोनों के लिए मान्य)।

चरण 1) प्रतिशत विस्तार बाएं से शुरू, प्रत्येक वर्ण को स्कैन करें %या के लिए <LF>। अगर मिल गया तो

  • 1.05 (छोटी लाइन पर <LF>)
    • अगर चरित्र है <LF>तो
      • <LF>आगे की ओर से शेष रेखा को छोड़ें (अनदेखा करें)
      • गोटो फेज 1.5 (स्ट्रिप <CR>)
    • पात्र होना चाहिए %, इसलिए 1.1 पर आगे बढ़ें
  • 1.1 (बच %) छोड़ दिया अगर कमांड लाइन मोड
    • यदि बैच मोड और उसके बाद दूसरे %को
      बदला %%जाता है तो सिंगल से बदलें %और स्कैन जारी रखें
  • 1.2 (विस्तार तर्क) अगर कमांड लाइन मोड बंद हो गया है
    • और अगर बैच मोड तो
      • तो द्वारा पीछा किया *और आदेश एक्सटेंशन तो सक्षम हैं,
        की जगह %*सभी आदेश पंक्ति तर्क के पाठ के साथ (कुछ भी नहीं के साथ बदलें अगर कोई तर्क हैं) और स्कैन जारी है।
      • वरना अगर द्वारा पीछा किया <digit>तो
        बदलें %<digit>तर्क मान के साथ (कुछ भी नहीं के साथ बदलें यदि अपरिभाषित) और स्कैन जारी है।
      • इसके बाद यदि ~कमांड और एक्सटेंशन एक्सटेंशन को सक्षम किया जाता है
        • यदि आवश्यक होने के <digit>बाद तर्क संशोधकों की वैकल्पिक मान्य सूची का पालन किया जाता है, तो संशोधित तर्क मान के साथ
          बदलें %~[modifiers]<digit>(परिभाषित नहीं होने पर या यदि निर्दिष्ट नहीं है तो $ PATH: संशोधक परिभाषित नहीं है) और स्कैन जारी रखें।
          नोट: संशोधक केस असंवेदनशील हैं और किसी भी क्रम में कई बार दिखाई दे सकते हैं, केवल $ PATH को छोड़कर: संशोधक केवल एक बार दिखाई दे सकता है और इससे पहले अंतिम संशोधक होना चाहिए<digit>
        • अतिरिक्त अमान्य संशोधित तर्क सिंटैक्स घातक त्रुटि को बढ़ाता है : सभी पार्स कमांड निरस्त कर दिए जाते हैं, और बैच मोड में बैच प्रोसेसिंग एबॉर्ट्स!
  • 1.3 (चर का विस्तार करें)
    • और यदि कमांड एक्सटेंशन अक्षम हैं तो
      वर्णों के अगले स्ट्रिंग को देखें, %बफर के पहले या अंत को तोड़कर , और उन्हें VAR कहें (यह एक खाली सूची हो सकती है)
      • अगर अगला किरदार है %तो
        • यदि VAR को परिभाषित किया गया है, तो VAR के मान से
          प्रतिस्थापित %VAR%करें और स्कैन जारी रखें
        • और यदि बैच मोड है तो
          निकालें %VAR%और स्कैन जारी रखें
        • एल्स गोटो 1.4
      • एल्स गोटो 1.4
    • और यदि कमांड एक्सटेंशन सक्षम हैं तो
      वर्णों के अगले स्ट्रिंग को देखें, % :बफर के पहले या अंत को तोड़कर , और उन्हें VAR कहें (यह एक खाली सूची हो सकती है)। यदि VAR पहले :और बाद के वर्ण को तोड़ता है %तो :VAR में अंतिम वर्ण के रूप में शामिल होता है और पहले टूट जाता है %
      • अगर अगला किरदार है %तो
        • यदि VAR को परिभाषित किया गया है, तो VAR के मान से
          प्रतिस्थापित %VAR%करें और स्कैन जारी रखें
        • और यदि बैच मोड है तो
          निकालें %VAR%और स्कैन जारी रखें
        • एल्स गोटो 1.4
      • आगे अगर चरित्र है :तो
        • यदि VAR अपरिभाषित है तो
          • यदि बैच मोड है तो
            निकालें %VAR:और स्कैन जारी रखें।
          • एल्स गोटो 1.4
        • आगे अगर चरित्र है ~तो
          • यदि वर्णों का अगला तार पैटर्न से मेल खाता है, [integer][,[integer]]%तो VAR के मान के
            प्रतिस्थापन के %VAR:~[integer][,[integer]]%साथ प्रतिस्थापित करें (संभवतः रिक्त स्ट्रिंग के परिणामस्वरूप) और स्कैन जारी रखें।
          • एल्स गोटो 1.4
        • यदि इसके बाद =या *=उसके बाद
          अमान्य चर खोज और सिंटैक्स की जगह घातक त्रुटि उठती है: सभी पार्स किए गए आदेश निरस्त किए जाते हैं, और बैच मोड में बैच प्रोसेसिंग एबॉर्ट्स!
        • यदि पात्रों के अगले स्ट्रिंग पैटर्न से मेल खाते हैं [*]search=[replace]%, जहां खोज में वर्णों के किसी भी सेट को शामिल किया जा सकता है =, और इसके अलावा वर्णों के किसी भी सेट को शामिल किया जा सकता है %, तो खोज करने के बाद VAR के मान को
          बदलें %VAR:[*]search=[replace]%और प्रतिस्थापित करें (संभवतः खाली स्ट्रिंग में जिसके परिणामस्वरूप) और जारी रखें स्कैन
        • एल्स गोटो 1.4
  • 1.4 (स्ट्रिप%)
    • एल्स यदि बैच मोड है, तो
      निकालें %और जारी रखने के बाद अगले चरित्र के साथ स्कैन करना जारी रखें%
    • एल्स प्रमुख को संरक्षित करते हैं %और संरक्षित अग्रणी के बाद अगले चरित्र के साथ स्कैन करना जारी रखते हैं%

उपरोक्त यह समझाने में मदद करता है कि यह बैच क्यों है

@echo off
setlocal enableDelayedExpansion
set "1var=varA"
set "~f1var=varB"
call :test "arg1"
exit /b  
::
:test "arg1"
echo %%1var%% = %1var%
echo ^^^!1var^^^! = !1var!
echo --------
echo %%~f1var%% = %~f1var%
echo ^^^!~f1var^^^! = !~f1var!
exit /b

ये परिणाम देता है:

%1var% = "arg1"var
!1var! = varA
--------
%~f1var% = P:\arg1var
!~f1var! = varB

नोट 1 - चरण 1 REM बयानों की मान्यता से पहले होता है। यह बहुत महत्वपूर्ण है क्योंकि इसका मतलब है कि एक टिप्पणी भी एक घातक त्रुटि उत्पन्न कर सकती है यदि इसमें अमान्य तर्क विस्तार सिंटैक्स या अमान्य वैरिएबल खोज है और सिंटैक्स को प्रतिस्थापित करें!

@echo off
rem %~x This generates a fatal argument expansion error
echo this line is never reached

नोट 2 -% पार्सिंग नियमों का एक और दिलचस्प परिणाम: चर युक्त: नाम में परिभाषित किया जा सकता है, लेकिन उन्हें तब तक नहीं बढ़ाया जा सकता जब तक कि कमांड एक्सटेंशन अक्षम न हों। एक अपवाद है - एक चर नाम जिसमें अंत में एक कोलन होता है, का विस्तार किया जा सकता है जबकि कमांड एक्सटेंशन सक्षम होते हैं। हालाँकि, आप किसी कॉलोन के साथ समाप्त होने वाले परिवर्तनशील नामों पर प्रतिस्थापन या खोज का काम नहीं कर सकते हैं। नीचे दी गई बैच फ़ाइल (जेब के सौजन्य से) इस व्यवहार को प्रदर्शित करती है

@echo off
setlocal
set var=content
set var:=Special
set var::=double colon
set var:~0,2=tricky
set var::~0,2=unfortunate
echo %var%
echo %var:%
echo %var::%
echo %var:~0,2%
echo %var::~0,2%
echo Now with DisableExtensions
setlocal DisableExtensions
echo %var%
echo %var:%
echo %var::%
echo %var:~0,2%
echo %var::~0,2%

नोट 3 - पार्सिंग नियमों के आदेश का एक दिलचस्प परिणाम जो जेब उसके पोस्ट में देता है: जब प्रदर्शन करते हैं और विलंबित विस्तार की जगह लेते हैं, तो दोनों को खोजने और बदलने वाले शब्दों में विशेष वर्णों को बच जाना चाहिए या उद्धृत किया जाना चाहिए। लेकिन प्रतिशत विस्तार के लिए स्थिति अलग है - खोज शब्द बच नहीं जाना चाहिए (हालांकि यह उद्धृत किया जा सकता है)। प्रतिशत की जगह स्ट्रिंग आपके इरादे के आधार पर भागने या उद्धरण की आवश्यकता हो सकती है या नहीं।

@echo off
setlocal enableDelayedExpansion
set "var=this & that"
echo %var:&=and%
echo "%var:&=and%"
echo !var:^&=and!
echo "!var:&=and!"

विलंबित विस्तार नियम

यहां जेब के उत्तर में चरण 5 का एक विस्तारित और अधिक सटीक विवरण दिया गया है (बैच मोड और कमांड लाइन मोड दोनों के लिए मान्य)

चरण 5) विलंबित विस्तार

यदि निम्न स्थितियाँ लागू होती हैं, तो यह चरण छोड़ दिया गया है:

  • विलंबित विस्तार अक्षम है।
  • कमांड एक पाइप के दोनों ओर एक कोष्ठक के भीतर होता है।
  • भेजे आदेश टोकन एक "नग्न" बैच स्क्रिप्ट, जिसका अर्थ यह साथ संबद्ध नहीं है है CALL, parenthesized ब्लॉक, आदेश संयोजन के किसी भी रूप ( &, &&या ||), या एक पाइप |

विलंबित विस्तार प्रक्रिया टोकन के लिए स्वतंत्र रूप से लागू की जाती है। एक कमांड में कई टोकन हो सकते हैं:

  • आज्ञा टोकन। अधिकांश आदेशों के लिए कमांड नाम ही एक टोकन है। लेकिन कुछ आदेशों में विशेष क्षेत्र हैं जिन्हें चरण 5 के लिए एक टोकन माना जाता है।
    • for ... in(TOKEN) do
    • if defined TOKEN
    • if exists TOKEN
    • if errorlevel TOKEN
    • if cmdextversion TOKEN
    • if TOKEN comparison TOKEN, जहां तुलना में से एक है ==, equ, neq, lss, leq, gtr, याgeq
  • तर्क टोकन
  • पुनर्निर्देशन का गंतव्य टोकन (प्रति पुनर्निर्देशन)

टोकन में कोई बदलाव नहीं किया गया है जिसमें शामिल नहीं है !

प्रत्येक टोकन के लिए जिसमें कम से कम एक होता है !, प्रत्येक वर्ण को बाएं से दाएं ^या के लिए स्कैन करें !, और यदि पाया जाता है, तो

  • ५.१ (कैरेट एस्केप) की आवश्यकता !या ^शाब्दिक
    • अगर किरदार एक कैरेट है ^तो
      • हटाए ^
      • अगले चरित्र को स्कैन करें और इसे एक शाब्दिक के रूप में संरक्षित करें
      • स्कैन जारी रखें
  • 5.2 (चर का विस्तार करें)
    • अगर चरित्र है !, तो
      • यदि कमांड एक्सटेंशन अक्षम हैं, तो
        वर्णों के अगले स्ट्रिंग को देखें, पहले तोड़कर , !या <LF>उन्हें VAR कहें (एक खाली सूची हो सकती है)
        • अगर अगला किरदार है !तो
          • यदि VAR को परिभाषित किया गया है, तो VAR के मान से
            प्रतिस्थापित !VAR!करें और स्कैन जारी रखें
          • और यदि बैच मोड है तो
            निकालें !VAR!और स्कैन जारी रखें
          • एल्से गोटो 5.2.1
        • एल्से गोटो 5.2.1
      • वरना अगर आदेश एक्सटेंशन सक्षम कर रहे हैं तो
        , वर्ण के अगले स्ट्रिंग को देखो से पहले तोड़ने !, :या <LF>, और उन्हें वीएआर फोन (एक खाली सूची हो सकता है)। यदि VAR पहले :और बाद के वर्ण को तोड़ता है !तो :VAR में अंतिम वर्ण के रूप में शामिल होता है और पहले टूट जाता है!
        • अगर अगला किरदार है !तो
          • यदि VAR मौजूद है, तो VAR का मान
            बदलें !VAR!और स्कैन जारी रखें
          • और यदि बैच मोड है तो
            निकालें !VAR!और स्कैन जारी रखें
          • एल्से गोटो 5.2.1
        • आगे अगर चरित्र है :तो
          • यदि VAR अपरिभाषित है तो
            • यदि बैच मोड है तो
              निकालें !VAR:और स्कैन जारी रखें
            • एल्से गोटो 5.2.1
          • आगे अगर चरित्र है ~तो
            • यदि वर्णों का अगला तार पैटर्न से मेल खाता है, [integer][,[integer]]!तो !VAR:~[integer][,[integer]]!VAR के मान के प्रतिस्थापन के साथ प्रतिस्थापित करें (संभवतः रिक्त स्ट्रिंग के परिणामस्वरूप) और स्कैन जारी रखें।
            • एल्से गोटो 5.2.1
          • यदि पात्रों के अगले स्ट्रिंग पैटर्न से मेल खाते हैं [*]search=[replace]!, जहां खोज में वर्णों के किसी भी सेट को शामिल किया जा सकता है =, और इसके अलावा वर्णों के किसी भी सेट को शामिल किया जा सकता है !, तो खोज करने के बाद VAR के मान को
            बदलें !VAR:[*]search=[replace]!और प्रतिस्थापित करें (संभवतः एक रिक्त स्ट्रिंग में जिसके परिणामस्वरूप) और स्कैन जारी रखें
          • एल्से गोटो 5.2.1
        • एल्से गोटो 5.2.1
      • 5.2.1
        • यदि बैच मोड है तो प्रमुख को हटा दें प्रमुख को !
          संरक्षित करें!
        • संरक्षित प्रमुख के बाद अगले चरित्र से शुरू होने वाले स्कैन को जारी रखें !

3
+1, केवल औपनिवेशिक वाक्यविन्यास और नियम यहाँ %definedVar:a=b%बनाम %undefinedVar:a=b%और %var:~0x17,-010%रूपों के लिए गायब हैं
jeb

2
अच्छा बिंदु - मैंने आपकी चिंताओं को दूर करने के लिए चर विस्तार अनुभाग का विस्तार किया। मैंने कुछ गुम विवरणों को भरने के लिए तर्क विस्तार खंड का भी विस्तार किया।
dbenham

2
जेब से कुछ अतिरिक्त निजी प्रतिक्रिया मिलने के बाद, मैंने कोलन के साथ समाप्त होने वाले चर नामों के लिए एक नियम जोड़ा, और नोट 2 जोड़ा। मैंने नोट 3 को केवल इसलिए भी जोड़ा क्योंकि मुझे लगा कि यह दिलचस्प और महत्वपूर्ण था।
dbenham

1
@aschipfl - हाँ, मैंने उस बारे में और विस्तार से जाना, लेकिन उस खरगोश के छेद से नीचे नहीं जाना चाहता था। जब मैं [पूर्णांक] शब्द का उपयोग करता था, तो मैं जानबूझकर गैर-कम्यूटल था। नियमों के बारे में अधिक जानकारी सीएमडी.ईएक्सई पार्स नंबरों को कैसे करता है
डेबनहम

1
मुझे cmd संदर्भ के लिए विस्तार नियम याद आ रहे हैं, जैसे कि चर नाम के पहले वर्ण के लिए कोई आरक्षित वर्ण नहीं हैं %<digit>, %*या %~। और अपरिभाषित चर के लिए व्यवहार बदलता है। शायद आपको दूसरा जवाब खोलने की जरूरत है
जेब

7

जैसा कि बताया गया है, कमांडों को μSoft भूमि में पूरे तर्क स्ट्रिंग को पारित किया जाता है, और यह उनके ऊपर है कि वे अपने स्वयं के उपयोग के लिए अलग-अलग तर्कों में इसे पार्स करें। अलग-अलग कार्यक्रमों के बीच इसमें कोई सामंजस्य नहीं है, और इसलिए इस प्रक्रिया का वर्णन करने के लिए नियमों का कोई एक सेट नहीं है। आपके प्रोग्राम का उपयोग करने वाले C लाइब्रेरी के लिए आपको वास्तव में प्रत्येक कोने के मामले की जांच करने की आवश्यकता है।

जहाँ तक सिस्टम .batफाइल्स का जाना है, यहाँ वह टेस्ट है:

c> type args.cmd
@echo off
echo cmdcmdline:[%cmdcmdline%]
echo 0:[%0]
echo *:[%*]
set allargs=%*
if not defined allargs goto :eof
setlocal
@rem Wot about a nice for loop?
@rem Then we are in the land of delayedexpansion, !n!, call, etc.
@rem Plays havoc with args like %t%, a"b etc. ugh!
set n=1
:loop
    echo %n%:[%1]
    set /a n+=1
    shift
    set param=%1
    if defined param goto :loop
endlocal

अब हम कुछ परीक्षण चला सकते हैं। देखें कि क्या आप यह पता लगा सकते हैं कि μSoft क्या करने की कोशिश कर रहा है:

C>args a b c
cmdcmdline:[cmd.exe ]
0:[args]
*:[a b c]
1:[a]
2:[b]
3:[c]

अब तक ठीक है। (मैं अब से निर्बाध %cmdcmdline%और बाहर छोड़ दूँगा %0।)

C>args *.*
*:[*.*]
1:[*.*]

कोई फ़ाइल नाम विस्तार नहीं।

C>args "a b" c
*:["a b" c]
1:["a b"]
2:[c]

कोई उद्धरण स्ट्रिपिंग नहीं, हालांकि उद्धरण तर्क विभाजन को रोकते हैं।

c>args ""a b" c
*:[""a b" c]
1:[""a]
2:[b" c]

लगातार दोहरे उद्धरण चिह्नों के कारण उनके पास कोई विशेष पार्सिंग क्षमता खो सकती है। @ बेनोइट का उदाहरण:

C>args "a """ b "" c"""
*:["a """ b "" c"""]
1:["a """]
2:[b]
3:[""]
4:[c"""]

क्विज़: आप किसी भी पर्यावरण संस्करण के मान को एक तर्क (यानी, जैसे %1) से बैट फ़ाइल में कैसे पास करते हैं?

c>set t=a "b c
c>set t
t=a "b c
c>args %t%
1:[a]
2:["b c]
c>args "%t%"
1:["a "b]
2:[c"]
c>Aaaaaargh!

साने पार्सिंग हमेशा के लिए टूटी हुई लगती है।

आपके मनोरंजन के लिए, विविध जोड़ने का प्रयास करें ^, \, ', &इन उदाहरणों को (और सी।) वर्ण।


% T% को एकल तर्क के रूप में पारित करने के लिए आप "% t:" = \ "%" का उपयोग कर सकते हैं, अर्थात, चर विस्तार के लिए% VAR: str = प्रतिस्थापन% सिंटैक्स का उपयोग करें। शेल मेटाचैकर जैसे | और चर सामग्री में अभी भी उजागर किया जा सकता है और शेल को गड़बड़ कर सकता है, जब तक कि आप उन्हें फिर से नहीं
बचाते हैं

@ तब, मेरे उदाहरण में, tहै a "b c। (आप उन 6 अक्षर प्राप्त करने के लिए एक नुस्खा है a, 2 × अंतरिक्ष, ", b, और c) के रूप में प्रकट करने के लिए %1एक के अंदर .cmd? मुझे आपकी सोच पसंद है। args "%t:"=""%"बहुत करीब है :-)
bobbogo

5

आपके पास पहले से ही कुछ बेहतरीन उत्तर हैं, लेकिन अपने प्रश्न के एक हिस्से का उत्तर देने के लिए:

set a =b, echo %a %b% c% → bb c%

वहाँ क्या हो रहा है, क्योंकि आपके पास = से पहले एक स्थान है, एक चर बनाया जाता है, %a<space>% इसलिए जब आपको echo %a %सही तरीके से मूल्यांकन किया जाता है b

b% c%फिर शेष भाग का मूल्यांकन सादे पाठ + अपरिभाषित चर के रूप में किया जाता है % c%, जिसे मेरे लिए echo %a %b% c%रिटर्न के रूप में टाइप किया जाना चाहिए।bb% c%

मुझे संदेह है कि परिवर्तनशील नामों में रिक्त स्थान शामिल करने की क्षमता एक नियोजित 'सुविधा' की तुलना में अधिक है।


0

संपादित करें: स्वीकृत उत्तर देखें, जो निम्न प्रकार गलत है और केवल यह बताता है कि टिनीपेरल को कमांड लाइन कैसे पारित की जाए।


उद्धरण के बारे में, मुझे लगता है कि व्यवहार निम्नलिखित है:

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

संक्षेप में:

"a """ b "" c"""दो तारों के होते हैं: a " b "औरc"

"a"", "a"""और "a""""यदि एक पंक्ति के अंत में सभी समान स्ट्रिंग हैं


टोकन और स्ट्रिंग ग्लोबिंग कमांड पर निर्भर करता है! एक "सेट" अलग काम करता है तो एक "कॉल" या यहां तक ​​कि एक "अगर"
जेब

हाँ, लेकिन बाहरी आदेशों के बारे में क्या? मुझे लगता है कि cmd.exe हमेशा उनके लिए एक ही तर्क देता है?
Benoit

1
cmd.exe हमेशा एक स्ट्रिंग के रूप में विस्तार के परिणाम को पारित करता है एक बाहरी कमांड को टोकन नहीं। यह बाहरी आदेश पर निर्भर करता है कि कैसे बचना है और इसे टोकना है, यह पता लगाता है कि बैकस्लैश का उपयोग अगले व्यक्ति कुछ और उपयोग कर सकता है
jeb

0

ध्यान दें कि Microsoft ने अपने टर्मिनल का स्रोत कोड प्रकाशित किया है। यह वाक्यविन्यास पार्सिंग के संबंध में कमांड लाइन के समान काम कर सकता है। शायद किसी को टर्मिनल के पार्सिंग नियमों के अनुसार रिवर्स-इंजीनियर पार्सिंग नियमों का परीक्षण करने में रुचि है।

स्रोत कोड से लिंक करें

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