HOWTO · Batch
在批处理脚本中创建函数
本教程将讨论如何在批处理脚本中创建函数。
本页内容
Batch 文件没有用于单独声明函数的关键字。可复用的子程序由标签定义,并通过 CALL 调用;CALL 会运行该标签之后的命令,然后返回到调用语句之后的下一条命令。这些示例使用 Windows CMD 语法,应保存为 Windows 上的 .bat 或 .cmd 文件后运行。
Batch 函数的工作方式
Batch 中所谓的“函数”通常称为子程序。标签名称标识入口,而 CALL :label 会将控制权转移到该入口,并保留返回位置。标签本身不会创建独立作用域,也不会自动返回。在子程序中使用 EXIT /B 返回调用方;若没有显式返回,执行可能继续进入后续标签和命令。如果当前批处理脚本不是作为子程序调用的,EXIT /B 会退出该脚本。
定义并调用 Batch 函数
将调用语句放在标签之前,然后在主程序主体末尾使用 GOTO :EOF,避免执行流程继续落入子程序。生成的脚本中,子程序会打印问候语并返回调用方。
若要查看一个小型 Windows CMD 脚本,同时避免误以为 CMD 已在此处运行,请运行这个 Python 脚本。它会打印 Batch 源码;将输出保存为 .bat 或 .cmd 文件,再在 Windows CMD 中运行。
本节中的代码以及显示的标签或输出仍为英文。
print('''@echo off
call :greet "Ada"
echo Back in the main script.
goto :eof
:greet
echo Hello, %~1!
exit /b 0''')
@echo off
call :greet "Ada"
echo Back in the main script.
goto :eof
:greet
echo Hello, %~1!
exit /b 0
生成的脚本面向 Windows CMD;Python 只会打印源码,不会执行它。GOTO :EOF 会结束主程序流程,而 EXIT /B 0 会让被调用的标签以成功状态返回。0 是惯用的成功代码;非零代码可向调用方报告失败。
向 Batch 函数传递参数
参数以空格分隔,跟在 CALL 命令中的标签之后。在子程序中,%1 是第一个参数,%2 是第二个参数,以此类推。如果需要去除第一个参数两侧可能存在的引号,建议使用 %~1;波浪号并不会让该值可以安全地插入任意命令,因此将值用作路径或文本时仍应加引号。
这个 Python 示例会打印一份完整的 Batch 脚本,其中传递了一个包含空格的参数;将打印出的源码保存为 .bat 或 .cmd 文件,即可在 Windows CMD 中运行。:show 子程序会通过 %~1 读取该值。
本节中的代码以及显示的标签或输出仍为英文。
print("""@echo off
call :show "Ada Lovelace"
goto :eof
:show
echo Name: %~1
exit /b 0""")
@echo off
call :show "Ada Lovelace"
goto :eof
:show
echo Name: %~1
exit /b 0
当参数值可能包含空格或命令元字符时,应在带引号的比较表达式或带引号的 SET 赋值中展开参数。Batch 解析分多个阶段进行,因此 %、& 和 | 等复杂值需要格外小心。
返回值和退出代码
Batch 没有内置的函数返回值位置。常见做法是将结果存入环境变量,并单独使用子程序的退出代码表示成功或失败。这个 Python 示例会打印一份完整的 Batch 脚本:脚本调用一个接收两个参数的子程序,在 CALL 之后立即检查其状态,并在成功时读取结果变量。将打印出的源码保存为 .bat 或 .cmd 文件,即可在 Windows CMD 中运行。
本节中的代码以及显示的标签或输出仍为英文。
print("""@echo off
setlocal EnableExtensions
call :add 5 10
if errorlevel 1 goto add_failed
echo Sum: %sum%
goto :eof
:add_failed
echo Addition failed.
goto :eof
:add
if "%~1"=="" exit /b 1
if "%~2"=="" exit /b 1
setlocal
set /a "_sum=%~1 + %~2"
endlocal & set "sum=%_sum%"
exit /b 0""")
@echo off
setlocal EnableExtensions
call :add 5 10
if errorlevel 1 goto add_failed
echo Sum: %sum%
goto :eof
:add_failed
echo Addition failed.
goto :eof
:add
if "%~1"=="" exit /b 1
if "%~2"=="" exit /b 1
setlocal
set /a "_sum=%~1 + %~2"
endlocal & set "sum=%_sum%"
exit /b 0
标签会将位置参数读取为 %~1 和 %~2。SETLOCAL 会将临时变量 _sum 限定在局部范围;在同一命令行中,CMD 会先展开 %_sum%,再运行 ENDLOCAL,随后将该值赋给调用方的 sum 变量。请将 ENDLOCAL & SET 保持在同一行。此示例要求参数为整数;缺少参数时返回状态码 1,加法完成时返回状态码 0。
处理 Batch 函数中的错误
应在子程序开头附近验证必需的输入;缺少输入时返回非零状态。这个 Python 示例会打印一份完整的 Batch 脚本,使用缺失输入和有效输入调用同一个验证标签;每个 if errorlevel 1 检查都会紧跟在相应的 CALL 之后。将打印出的源码保存为 .bat 或 .cmd 文件,即可在 Windows CMD 中运行。
本节中的代码以及显示的标签或输出仍为英文。
print("""@echo off
call :require_value
if errorlevel 1 (
echo Missing input: rejected with status 1.
) else (
echo Missing input: accepted.
)
call :require_value "report.txt"
if errorlevel 1 (
echo Valid input: rejected.
) else (
echo Valid input: accepted with status 0.
)
goto :eof
:require_value
if "%~1"=="" exit /b 1
exit /b 0""")
@echo off
call :require_value
if errorlevel 1 (
echo Missing input: rejected with status 1.
) else (
echo Missing input: accepted.
)
call :require_value "report.txt"
if errorlevel 1 (
echo Valid input: rejected.
) else (
echo Valid input: accepted with status 0.
)
goto :eof
:require_value
if "%~1"=="" exit /b 1
exit /b 0
第一次调用时,必需值缺失,因此会进入失败分支;第二次调用会进入成功分支。if errorlevel 1 表示当前错误级别大于或等于 1;如果需要判断具体代码,应按降序检查较高的代码。有效参数可以继续执行子程序的工作,并以 EXIT /B 0 结束。
子程序应使用 EXIT /B 返回,而不是使用 EXIT:EXIT 会关闭 CMD 会话,EXIT /B 则会从当前批处理上下文返回。如果 CALL 指向不存在的标签,CMD 会报告错误;统一标签拼写,并让子程序调用与对应标签清晰配对,有助于诊断此类问题。Python 示例打印的是 Batch 源码,并不会执行它;要观察 Batch 的运行行为,请在 Windows CMD 中运行保存后的脚本。