2010-07-12 11 views
14

मुझे मेरी बैच फ़ाइल में कोई समस्या है। वह कुछ इस तरह कर रही द्वारा स्वचालित रूप से कई कार्यक्रमों बनाता है:फ़ंक्शन के अंदर से बाहर निकलें बैच स्क्रिप्ट

  • सेट कुछ संकलन झंडे
  • रन
  • कॉल "त्रुटि के स्तर की जाँच" समारोह 'सभी gmake' और अगर errorlevel 1, बाहर निकलें

तो यह इस तरह दिखता है:

set FLAG=1 
... 
gmake all 
call :interactive_check 
set OTHERFLAG=1 
... 
gmake all 
call :interactive_check 

है 6 या इनमें से 7 (और मैं टी बढ़ सकता है)। इसलिए मैंने प्रत्येक चरण में प्रतिलिपि बनाने/चिपकाने के बजाय त्रुटिलेवल की जांच करने के लिए एक फ़ंक्शन बनाया। समस्या यह है: त्रुटि जाँच एक समारोह के माध्यम से किया जाता है:

:interactive_check 
if errorlevel 1 (
echo. 
echo /!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\ 
echo Error in compilation process... exiting 
echo /!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\ 
echo. 
cd %root_dir% 
exit /B 1 
) ELSE (
echo.Continuing to next step 
) 
goto:eof 

अब, जब यह चल रहा है, exit /B 1 बस समारोह, नहीं बल्कि बैच फ़ाइल बाहर निकालता है।

क्या आप जानते हैं कि पूर्ण बैच फ़ाइल से बाहर निकलने के बिना प्रत्येक चरण में "अगर त्रुटि 1 .." प्रतिलिपि/चिपकाए बिना?

+2

आप नहीं कर सकते। 'If ​​errorlevel 1 goto error' के साथ बस 'कॉल: इंटरएक्टिव_चेक'' को प्रतिस्थापित करें। पूर्व या बाद की प्रतिलिपि बनाने के बीच बहुत अंतर नहीं है। :) – atzz

+0

समझ गया, इस के साथ समस्या हल हो गई और यह ठीक काम करता है, धन्यवाद! – Gui13

उत्तर

16

एक घातक सिंटैक्स त्रुटि का उपयोग करना, के रूप में जेब को दर्शाता है, सभी बैच प्रोसेसिंग मारने करता है, लेकिन यह भी एक बुरा पक्ष प्रभाव पड़ता है - SETLOCAL के बाद पर्यावरण परिवर्तन संरक्षित कर रहे हैं, भले ही वे निहित ENDLOCAL के माध्यम से खारिज किया जा करने वाले हैं जब बैच प्रसंस्करण समाप्त होता है। अधिक जानकारी के लिए मेरे डॉसटिप्स SETLOCAL continues after batch termination! पोस्ट करें।

Why does a non-interactive batch script think I've pressed control-C? पर जानकारी के आधार पर, मैंने कॉल किए गए दिनचर्या या स्क्रिप्ट के भीतर से सभी बैच स्क्रिप्टिंग से बाहर निकलने के लिए एक साफ तरीका खोज लिया है, और सेटोकल के बाद सभी परिवर्तन ठीक से त्याग दिए गए हैं।

@echo off 
setlocal 
set test=AFTER main SETLOCAL 
call :sub 
echo returning from main NEVER REACHED 
exit /b 

:sub 
setlocal 
set test=AFTER sub SETLOCAL 
set test 
call :ExitBatch 
echo returning from sub2 NEVER REACHED 
exit /b 


:ExitBatch - Cleanly exit batch processing, regardless how many CALLs 
if not exist "%temp%\ExitBatchYes.txt" call :buildYes 
call :CtrlC <"%temp%\ExitBatchYes.txt" 1>nul 2>&1 
:CtrlC 
cmd /c exit -1073741510 

:buildYes - Establish a Yes file for the language used by the OS 
pushd "%temp%" 
set "yes=" 
copy nul ExitBatchYes.txt >nul 
for /f "delims=(/ tokens=2" %%Y in (
    '"copy /-y nul ExitBatchYes.txt <nul"' 
) do if not defined yes set "yes=%%Y" 
echo %yes%>ExitBatchYes.txt 
popd 
exit /b 

उपर्युक्त test.bat चलाने का नमूना आउटपुट यहां दिया गया है। आप देख सकते हैं कि स्क्रिप्ट कभी भी वापस नहीं आया: ExitBatch कॉल, और बैच प्रोसेसिंग समाप्त होने के बाद परीक्षण चर परिभाषा को ठीक से हटा दिया गया है।

C:\test>test.bat 
test=AFTER sub SETLOCAL 

C:\test>set test 
Environment variable test not defined 

C:\test> 

: ExitBatch दिनचर्या को अपने स्वयं के ExitBatch में रखा जा सकता है।बल्ले स्क्रिप्ट और अपने पैथ के भीतर कहीं भी रखा गया है कि इसे किसी भी बैच स्क्रिप्ट द्वारा आसानी से उपयोग किया जा सकता है।

@echo off 
:ExitBatch - Cleanly exit batch processing, regardless how many CALLs 
if not exist "%temp%\ExitBatchYes.txt" call :buildYes 
call :CtrlC <"%temp%\ExitBatchYes.txt" 1>nul 2>&1 
:CtrlC 
cmd /c exit -1073741510 

:buildYes - Establish a Yes file for the language used by the OS 
pushd "%temp%" 
set "yes=" 
copy nul ExitBatchYes.txt >nul 
for /f "delims=(/ tokens=2" %%Y in (
    '"copy /-y nul ExitBatchYes.txt <nul"' 
) do if not defined yes set "yes=%%Y" 
echo %yes%>ExitBatchYes.txt 
popd 
exit /b 

महत्वपूर्ण अपडेट:

अब यह मजबूत अपवाद शुद्ध बैच के साथ निपटने के लागू करने के लिए संभव है। न केवल आप एक अपवाद फेंक सकते हैं जो किसी भी कॉल स्तर से सभी बैच प्रोसेसिंग को समाप्त कर सकता है, लेकिन आप उच्च स्तर पर अपवाद भी पकड़ सकते हैं, विशेष अपवाद हैंडलिंग क्लीनअप कोड को समाप्त कर सकते हैं, और प्रसंस्करण फिर से शुरू कर सकते हैं, या किसी अन्य फेंक के माध्यम से बाहर निकलना जारी रख सकते हैं! अधिक जानकारी के लिए Does Windows batch support exception handling? देखें।

@echo off 

:: comment next line if you want to export any local variables in caller environment 
setlocal 

set FLAG=1 
rem Do something 
call :interactive_check 

set FLAG2=2 
rem Do something 
call :interactive_check 

goto :eof 

:interactive_check 
if errorlevel 1 (
    echo. 
    echo /!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\ 
    echo Error in compilation process... exiting 
    echo /!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\ 
    (goto) 2>nul & endlocal & exit /b %ERRORLEVEL% 
) else (
    echo Continuing to next step 
) 
goto :eof 

यह आदेश जो त्रुटि उत्पन्न से त्रुटि कोड की बचत होती है:

+0

इंजेनिअस। खुशी है कि आप मेरी खोज को इतनी जल्दी अच्छे काम में डाल सकते हैं; लगभग मूल रूप से मुझे परेशान करने के लिए बनाता है। :-) –

+0

ठीक है, आप एक स्वीकृति के योग्य हैं, महोदय। – Gui13

+0

सामान्य समाधान के लिए मेरा समाधान क्लीनर के लिए अच्छा समाधान। – jeb

20

एक अच्छा समाधान के लिए भाग उन्नत संस्करण

देखने के लिए आप किसी भी बिंदु पर एक बैच को रोक सकता है, यह भी नेस्टेड फ़ंक्शन कॉल के अंदर।

आपको केवल एक वाक्यविन्यास त्रुटि बनाने की आवश्यकता है, उदाहरण के लिए त्रुटि संदेश को दबाने के लिए खाली ब्लॉक () के साथ, इसे कॉल में निष्पादित किया जा सकता है, और कॉल के stderr को nul पर रीडायरेक्ट किया जाता है।

@echo off 
setlocal enabledelayedexpansion 

rem Do something 
call :interactive_check 

rem Do something 
call :interactive_check 

goto :eof 

:::::::::::::::::::::::::: 
:interactive_check 
if errorlevel 1 (
    echo. 
    echo /!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\ 
    echo Error in compilation process... exiting 
    echo /!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\ 
    call :halt 1 
) ELSE (
    echo.Continuing to next step 
) 
goto :eof 

:: Sets the errorlevel and stops the batch immediately 
:halt 
call :__SetErrorLevel %1 
call :__ErrorExit 2> nul 
goto :eof 

:__ErrorExit 
rem Creates a syntax error, stops immediately 
() 
goto :eof 

:__SetErrorLevel 
exit /b %time:~-2% 
goto :eof 

2017-04-09 उन्नत संस्करण: बाहर निकलें केवल मौजूदा बैच, लेकिन नहीं फोन करने वाले बैच

@dbenham उल्लेख किया है, वहाँ वह भी इस्तेमाल किया जा सकता अपवाद संचालन के लिए एक नई कलाओं है केवल मौजूदा बैच से बाहर निकलने के लिए।

@echo off 
echo Do something, detecting some fatal error 
call :ExitBatch 3 
exit /b 

:ExitBatch [errorcode] - Exits only the current batch file, regardless how many CALLs 
set _errLevel=%1 
REM *** Remove all calls from the current batch from the call stack 
:popStack 
(
    (goto) 2>nul 
    setlocal DisableDelayedExpansion  
    call set "caller=%%~0" 
    call set _caller=%%caller:~0,1%% 
    call set _caller=%%_caller::=%% 
    if not defined _caller (
     REM callType = func 
     rem set _errLevel=%_errLevel% 
     goto :popStack 
    ) 
    (goto) 2>nul 
    endlocal 
    cmd /c "exit /b %_errLevel%" 
) 
echo NEVER REACHED 
exit /b 
+0

कूल समाधान :) मैंने एटज़ के सुझाव का उपयोग कर समस्या हल की, लेकिन अगर कोई यहां ठोकर खाए, तो आप जवाब देंगे। – Gui13

+1

यह समाधान अनुसूचित जाति के बाद पर्यावरण परिवर्तनों को अनुचित रूप से संरक्षित करेगा। मैंने एक [स्वच्छ समाधान] (http://stackoverflow.com/a/25474648/1012053) खोजा है जो SETLOCAL के बाद सभी परिवर्तनों को ठीक से हटा देता है। – dbenham

1

मैं निम्नलिखित समाधान सुझाव देते हैं। ,

(goto) 2>nul & endlocal & exit /b YOUR_EXITCODE_HERE 

मैं सिंटैक्स त्रुटि वाला समाधान (jeb's post देखें) पसंद नहीं है, क्योंकि यह भी वर्तमान बैच फ़ाइल के फोन करने वाले भी समाप्त हो जाता है: यदि आप विशिष्ट मूल्य के लिए त्रुटि कोड को बचाने के लिए चाहते हैं, तो लाइन को संशोधित।

1

जब आप exit /b X का उपयोग फ़ंक्शन से बाहर निकलने के लिए करते हैं तो यह के मान पर ERRORLEVEL सेट करता है। के बाद ERRORLEVEL गैर-शून्य होने पर आप अन्य कमांड निष्पादित करने के लिए ||conditional processing symbol का उपयोग कर सकते हैं। इस स्क्रिप्ट से

@echo off 
setlocal 
call :myfunction PASS || goto :eof 
call :myfunction FAIL || goto :eof 
echo Execution never gets here 
goto :eof 

:myfunction 
    if "%1"=="FAIL" ( 
     echo myfunction: got a FAIL. Will exit. 
     exit /b 1 
    ) 
    echo myfunction: Everything is good. 
    exit /b 0 

आउटपुट है:

myfunction: Everything is good. 
myfunction: got a FAIL. Will exit. 
संबंधित मुद्दे