Что-то вроде функции / метода в пакетных файлах?
Есть ли что-нибудь, что имитирует метод, подобный тому, который известен по Java, C# и т. д.? У меня есть 5 строк команд в командном файле, эти 5 строк используются в нескольких местах внутри командного файла. Я не могу использовать goto, потому что в зависимости от уровня ошибки, созданного этими 5 строками, у меня есть следующие действия. Я попытался поместить свои 5 строк в пакетный файл 5lines.bat, но оригинальный пакетный файл original.bat вызывает только 5lines.bat и не выполняет команды после вызова 5lines.bat): так выглядит мой original.bat лайк:
5lines.bat
echo this gets never called, how to make sure this gets called?
В 5lines.bat нет выхода или что-то в этом роде! Как я могу убедиться, что строка после 5lines.bat будет вызвана?
10 ответов
Размещение повторно используемых функций в отдельном пакетном файле, безусловно, будет работать для имитации функции.
Уловка в том, что вы должны использовать call
команда, чтобы гарантировать, что управление возвращается к вызывающей стороне после завершения выполнения второго пакетного файла.
call 5lines.bat
echo this will now get called
Вы можете использовать команду вызова:
call:myDosFunc
А затем определите функцию следующим образом:
:myDosFunc - here starts the function
echo. here the myDosFunc function is executing a group of commands
echo. it could do a lot of things
goto:eof
Источник: Пакетные функции
Просто для полноты вы можете также передать параметры в функцию:
Вызов функции
call :myDosFunc 100 "string val"
Тело функции
:myDosFunc
echo. Got Param#1 %~1
echo. Got Param#2 %~2
goto :eof
Решение:
@ECHO OFF
call:header Start Some Operation
... put your business logic here
... make sure EXIT below is present
... so you don't run into actual functions without the call
call:header Operation Finished Successfully
EXIT /B %ERRORLEVEL%
:: Functions
:header
ECHO =================================================
ECHO %*
ECHO =================================================
EXIT /B 0
Важно поставить EXIT /B в конце каждой функции, а также до начала определения функций, в моем примере это:
EXIT /B% ERRORLEVEL%
Исходя из опыта Java, я попытался включить некоторые знакомые соглашения при создании процедур для
.bat
скрипты.
Приведенный ниже сценарий демонстрирует определение двух процедур.
@ECHO OFF
SET firstInstanceVariable="Hello world!"
SET secondInstanceVariable="Good bye world!"
GOTO:MAIN
:firstMethodName
SETLOCAL ENABLEDELAYEDEXPANSION
SET firstArgumentPassedIn=%~1
SET secondArgumentPassedIn=%~2
ECHO %firstInstanceVariable%
ECHO "The first argument passed in was %firstArgumentPassedIn%"
ECHO "The second argument passed in was %secondArgumentPassedIn%"
ENDLOCAL
EXIT /B 0
:secondMethodName
SETLOCAL ENABLEDELAYEDEXPANSION
SET firstArgumentPassedIn=%~1
SET secondArgumentPassedIn=%~2
ECHO %secondInstanceVariable%
ECHO "The first argument passed in was %firstArgumentPassedIn%"
ECHO "The second argument passed in was %secondArgumentPassedIn%"
ENDLOCAL
EXIT /B 0
:MAIN
call:firstMethodName "The Quick Brown" "Fox Jumps Over"
call:secondMethodName "1 2 3 4" 3.14
Обратите внимание, что явный
GOTO:MAIN
необходимо пропустить определения процедур. Это потому, что вы должны пропустить процедуру, прежде чем решите ее прочитать. В противном случае процедура будет выполнена.
Приведенный ниже код демонстрирует близкий Java-эквивалент приведенного выше
.bat
сценарий.
public class MyObject {
private String firstInstanceVariable = "Hello world!";
private String secondInstanceVariable = "Good bye world!";
public void firstMethodName(Object... arguments) {
String firstArgumentPassedIn = arguments[0].toString();
String secondArgumentPassedIn = arguments[1].toString();
System.out.println(firstInstanceVariable);
System.out.format("The first argument passed in was %s", firstArgumentPassedIn);
System.out.format("The second argument passed in was %s", secondArgumentPassedIn);
}
public void secondMethodName(Object... arguments) {
String firstArgumentPassedIn = arguments[0].toString();
String secondArgumentPassedIn = arguments[1].toString();
System.out.println(secondInstanceVariable);
System.out.format("The first argument passed in was %s", firstArgumentPassedIn);
System.out.format("The second argument passed in was %s", secondArgumentPassedIn);
}
public static void main(String[] args) {
MyObject myObject = new MyObject();
myObject.firstMethodName("The Quick Brown", "Fox Jumps Over");
myObject.secondMethodName(new Integer[]{1,2,3,4}, 3.14);
}
}
Вы можете попробовать использовать примеры, перечисленные на этой странице
Кроме того, вы можете поместить общие строки в другой пакетный файл, который вы вызываете из основного
Вот "хак", который позволит вам иметь "анонимные" функции в пакетных файлах:
@echo off
setlocal
set "anonymous=/?"
:: calling the anonymous function
call :%%anonymous%% a b c 3>&1 >nul
:: here the anonymous function is defined
if "%0" == ":%anonymous%" (
echo(
echo Anonymous call:
echo %%1=%1 %%2=%2 %%3=%3
exit /b 0
)>&3
::end of the anonymous function
Блок анонимной функции должен быть помещен сразу после оператора вызова и должен заканчиваться оператором выхода
Хитрость в том, что CALL
внутренне использует GOTO
а затем возвращается к строке, где CALL
был выполнен. При двойном расширении GOTO выдается справочное сообщение (с %%/?%%
аргумент), а затем продолжает сценарий. Но после того, как это закончено, это возвращается к CALL
- вот почему заявление if необходимо.
Еще один замечательный учебник по написанию кода для многоразовых командных файлов - см . Превосходную библиотеку Ричи Лоуренса.
Я не уверен, было ли это очевидно из других ответов, но для ясности я публикую этот ответ. Я нашел другие ответы полезными в написании кода ниже.
echo what
rem the third param gives info to which label it should comeback to
call :myDosFunc 100 "string val" ComeBack
:ComeBack
echo what what
goto :eof
:myDosFunc
echo. Got Param#1 %~1
echo. Got Param#2 %~2
set returnto=%~3
goto :%returnto%
Ниже может выглядеть как функция.
call :myFunc %para1% %para2%
:myFunc <para1> <para2>
echo %1
echo %2
EXIT /B
Пример
@echo off
echo PROGRAM_NAME:%~nx0 Start
echo.
================================
SET debugMode=%1
call :myFunc1 %debugMode%
call :myFunc2 para1 "para2 hello"
================================
echo PROGRAM_NAME:%~nx0 End & pause>nul
EXIT /B
:: 👇 define the function under below
:myFunc1 <isDebug>
:: So that you can know the %1 means: isDebug.
if "%1" == "1" (
echo debug mode
)
EXIT /B
:myFunc2 <para1> <para2>
:: output: para1
echo %1
:: output: "para2 hello"
echo %2
EXIT /B