2011-12-12 9 views
14

अगर मैं निम्नलिखित विंडोज बैच कोड स्निपेट लेने के लिए और इसे चलाने:(विंडोज़ बैच) गोटो अगर ब्लॉक बहुत अजीब व्यवहार के भीतर

echo foo 
if 1 == 1 (
    echo bar 
    goto asdf 
    :asdf 
    echo baz 
) else (
    echo quux 
)

उत्पादन मैं उम्मीद होती है:

foo 
bar 
baz

लेकिन बजाय मैं:

foo 
bar 
baz 
quux

अगर मैं बाहर टिप्पणी goto asdf लाइन, यह उत्पादन मैं उम्मीद देता है। echo quux लाइन को कभी भी निष्कासित नहीं किया जाना चाहिए, तो गेटो का अस्तित्व क्यों होता है?

अद्यतन:

goto BEGIN 

:doit 
    echo bar 
    goto asdf 
    :asdf 
    echo baz 
    goto :EOF 

:BEGIN 

echo foo 
if 1 == 1 (
    call :doit 
) else (
    echo quux 
)

बहरहाल, यह अपने मूल सवाल का जवाब नहीं है: क्या इसके लायक है के लिए, यहाँ एक समाधान के सही ढंग से क्या मैं मूल रूप से करना है कि है।

उत्तर

23

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

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

पार्स चरण के बाद, जटिल आदेश स्मृति से निष्पादित किया जाता है। आईएफ खंड ठीक से संसाधित किया जाता है और ईएलएसई खंड ठीक से छोड़ दिया जाता है। लेकिन IF (सत्य) खंड के भीतर, आप GOTO :asdf निष्पादित करते हैं, इसलिए CMD.EXE ड्यूटीफली लेबल के लिए स्कैनिंग शुरू करता है। यह आईएफ/ईएलएसई के अंत में शुरू होता है और फ़ाइल के निचले भाग तक स्कैन करता है, शीर्ष पर वापस लूप करता है, और जब तक यह लेबल नहीं पाता तब तक स्कैन करता है। लेबल आपके आईएफ क्लॉज के भीतर होता है, लेकिन लेबल स्कैनर उस विवरण के बारे में कुछ भी नहीं जानता है। तो जब जटिल कमांड स्मृति से निष्पादित करता है, तो बैच प्रोसेसिंग जटिल IF/ELSE के अंत से लेबल से फिर से शुरू होता है।

तो इस बिंदु पर बैच प्रोसेसर देखता है और अगले कुछ लाइनों

echo baz 
) else (
    echo quux 
) 

baz गूँजती है निष्पादित करता है, और इसलिए quux है। लेकिन आप पूछ सकते हैं, "क्यों ) else ( नहीं है और/या ) में सिंटेक्स त्रुटि उत्पन्न बाद से वे अब असंतुलित और अब बड़ा अगर बयान के भाग के रूप में पार्स कर रहे हैं?

क्योंकि कैसे ) नियंत्रित किया जाता है की है कि।

यदि वहाँ एक खुला ( सक्रिय जब ) का सामना करना पड़ा है, तो ) के रूप में आप उम्मीद करेंगे संसाधित किया जाता है।

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

+2

+1 अच्छा स्पष्टीकरण, डेव। एक छोटा सा यह है: जब 'GOTO' निष्पादित किया जाता है * सक्रिय * 'FOR/IF' आदेश रद्द कर दिया जाता है और बैच फ़ाइल लेबल से जारी होती है। – Aacini

5

ब्रैकेट्स के एक सेट के अंदर कुछ भी एक हिट में एक पंक्ति, संसाधित, व्याख्या और निष्पादित किया जाता है।आपकी स्क्रिप्ट goto asdf तक पहुंचती है और उस ब्लॉक/रेखा से बाहर निकलती है। :asdf लेबल पर, कोई ब्रैकेट नहीं है, इसलिए यह लाइनों को एक-एक करके पढ़ना शुरू कर देता है। यह else तक पहुंचता है, लेकिन if:asdf और else के बीच कोई नहीं है, इसलिए यह इसे अनदेखा करता है।

इस तरह की समस्या से बचने के लिए, मैं हमेशा if और for बयान पर goto या call उपयोग करते हैं, बल्कि ब्लॉक से। यह goto कथन के साथ मुद्दों को हल करता है और चर के साथ भी कई समस्याएं उत्पन्न करता है।

goto का उपयोग करें:

echo foo 
if 1 == 1 goto bar 
echo quux 
goto nextbit 

:bar 
echo bar 
goto asdf 
:asdf 
echo baz 

:nextbit 
:: more script... 

या call उपयोग करने के लिए:

echo foo 
if 1 == 1 (call :bar) else (call :quux) 
:: more script... 
exit /b 

:bar 
echo bar 
goto asdf 
:asdf 
echo baz 
exit /b 

:quux 
echo quux 
exit /b 
0

इस मामले यह पता चला है एक अगर बयान के अंदर गरीब घोंसले और एक पाश की संरचना से संबंधित हो करने के लिए, जैसा कि ऊपर https://stackoverflow.com/users/1012053/dbenham द्वारा स्पष्ट रूप से समझाया गया है।

यही कहा, मैं पता लगा एक और इसी तरह विचार इस समस्या की वजह से ... कृपया एक बार देख ले एक निम्न समस्या और यहाँ बाद में समाधान: ". was unexpected at this time" generated from batch script line 'if exist [file] (...

समाधान बस '(' के उपचार था और ')' एक आईएफ स्टेटमेंट ब्लॉक के अंदर ईसीएचओ लाइनों पर।

बिंदु यह है कि समस्या निवारण IF (और संभवतः FOR) कथन के दौरान किसी विशेष समस्या के संभावित स्रोत के रूप में विशेष वर्णों के उपचार पर विचार करें।

एचटीएच

संबंधित मुद्दे