Что-то вроде функции / метода в пакетных файлах?

Есть ли что-нибудь, что имитирует метод, подобный тому, который известен по 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
Другие вопросы по тегам