类似于批处理文件中的函数/方法?

有没有什么方法可以模仿 Java、 C # 等等的方法?我在一个批处理文件中有5行命令,这5行命令在批处理文件中的多个位置使用。我不能使用 goto,因为根据这5行创建的错误级别,我有不同的动作。我尝试将我的5行代码放入一个批处理文件5lines.bat 中,但是原来的批处理文件 Origal.bat 只调用5lines.bat,并且在调用5lines.bat 之后不执行命令) : 这就是我的 Origal.bat 的样子:

5lines.bat
echo this gets never called, how to make sure this gets called?

在5lines.bat 中没有出口或类似的东西! 我怎么才能确保5lines.bat 后面的那条线被调用?

101355 次浏览

您可以使用 call 命令:

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命令,以确保在第二个批处理文件执行完毕后控制返回给调用者。

call 5lines.bat
echo this will now get called

您可以尝试使用 DOS 批处理-功能教程中列出的示例

或者,您可以将公共行放入从主文件调用的另一个批处理文件中

有关编写可重用批处理文件代码的另一个很棒的教程,请参见 里奇 · 劳伦斯的精美图书馆

解决方案:

@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 非常重要,在我的例子中是:

出口/B% 错误级别%

下面是一个允许你在批处理文件中使用 “匿名”函数的“黑客技术”:

@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 语句之后,并且必须以 exit 语句结束

诀窍在于,CALL在内部使用 GOTO,然后返回到执行 CALL的行。通过双扩展 GOTO 帮助消息被触发(使用 %%/?%%参数) ,然后继续脚本。但是在完成之后,它返回到 CALL-这就是为什么需要 if 语句。

为了完整起见,您还可以将参数传递给函数:

函数调用

call :myDosFunc 100 "string val"

功能体

:myDosFunc
echo. Got Param#1 %~1
echo. Got Param#2 %~2
goto :eof

我不知道这是否从其他答案是明显的,但只是为了明确,我张贴这个答案。我发现其他答案对于编写下面的代码很有帮助。

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%

出于 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。 这是因为在决定读取该过程之前,必须跳过该过程。否则,将执行该过程。

下面的代码演示了一个与上面的 .bat脚本非常接近的 Java 等价物。

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);
}
}

下面可能使它看起来像一个函数。

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