在我的主批处理文件中,我包含另一个批处理文件,并希望调用其中定义的函数,代码如下所示:
@echo off
call define_wait.bat
if "%1"=="WAIT" (
call :WAIT_AND_PRINT 5
echo.
)
REM rest...
我的 define_wait.bat 如下所示:
:WAIT_AND_PRINT
set /a time=%1
for /l %%x in (1, 1, %time%) do (
ping -n 1 -w 1000 1.0.0.0 > null
echo|set /p=.
)
goto :EOF
:WAIT
set /a time="%1 * 1000"
ping -n 1 -w %time% 1.0.0.0 > null
goto :EOF
问题是,如果我在另一个批处理文件中定义等待函数它不起作用,则调用call :WAIT_AND_PRINT 5
不会正确传递参数(错误:缺少操作数)。如果我从我的主批处理文件中的 define_wait.bat 复制我的代码,一切正常......
我如何正确地做到这一点?
答案 0 :(得分:3)
工作功能棒将其参数转发给它的子功能:
@echo off
call %*
goto :EOF
:WAIT_AND_PRINT
set /a time=%1
for /l %%x in (1, 1, %time%) do (
ping -n 1 -w 1000 1.0.0.0 > null
echo|set /p=.
)
goto :EOF
:WAIT
set /a time="%1 * 1000"
ping -n 1 -w %time% 1.0.0.0 > null
goto :EOF
在主蝙蝠中,我现在不再包含批处理文件,而是直接调用它,如下所示:
call define_wait.bat :WAIT_AND_PRINT 5
答案 1 :(得分:3)
我在jeb commented it之前没有意识到这一点,但这里有一个他提到的call
错误的快速演示,使用了我所处的一些实用功能。
<强> functions.bat:强>
:length <"string">
rem // sets errorlevel to the string length (not including quotation marks)
setlocal disabledelayedexpansion
if "%~1"=="" (endlocal & exit /b 0) else set ret=1
set "tmpstr=%~1"
for %%I in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
setlocal enabledelayedexpansion
if not "!tmpstr:~%%I,1!"=="" (
for %%x in ("!tmpstr:~%%I!") do endlocal & (
set /a ret += %%I
set "tmpstr=%%~x"
)
) else endlocal
)
endlocal & exit /b %ret%
:password <return_var>
rem // prompts user for password, masks input, and sets return_var to entered value
setlocal disabledelayedexpansion
<NUL set /P "=Password? "
set "psCommand=powershell -noprofile "$p=read-host -AsSecureString;^
$m=[Runtime.InteropServices.Marshal];$m::PtrToStringAuto($m::SecureStringToBSTR($p))""
for /f "usebackq delims=" %%p in (`%psCommand%`) do endlocal & set "%~1=%%p"
goto :EOF
<强> main.bat:强>
@echo off & setlocal
rem // demo return value
call :password pass
setlocal enabledelayedexpansion
echo You entered !pass!
rem // demo bubbling up of %ERRORLEVEL%
call :length "!pass!"
echo Password length is %ERRORLEVEL%
endlocal
goto :EOF
rem // ====== FUNCTION DECLARATIONS =======
:length <"string">
:password <return_var>
functions.bat %*
输出:
密码? *********
你输入了一些东西 密码长度为9
This web page提供了解释:
如果使用CALL执行第二个批处理文件而不使用,则可能会遇到一些错误的行为:如果两个批处理文件都包含一个具有相同名称的标签,并且您之前使用过CALL跳转到该标签在第一个脚本中,您将发现第二个脚本的执行从同一标签开始。即使第二个标签不存在,仍然会引发错误“找不到批处理标签”。总是使用CALL可以避免这个错误。
如果您曾在C ++中进行过任何编码,那么将main.bat中的标签视为.h文件中的函数声明是有帮助的,而functions.bat中的标签则对应在.cpp文件中运行 definitions 。或者在.NET中,main.bat标签可能就像DllImport("functions.bat")
一样。
答案 2 :(得分:2)
尽管有多种方法可以调用驻留在单独的库文件中的函数,但所有方法都需要更改调用程序中调用库函数的方式,和/或插入其他代码在库文件的开头,以便识别被调用的函数。
有一个有趣的技巧可以避免所有这些细节,因此main文件和库文件都包含原始代码,只需要将2行添加到主文件中。该方法包括将正在运行的主Batch文件的上下文切换到库文件;之后,库文件中的所有函数都可用于正在运行的代码。这样做的方法是重命名具有相同主文件名的库文件。之后,当执行call :function
命令时,:function
标签将在库文件中搜索!当然,在程序结束之前,必须将文件重命名为原始名称。啊!我几乎忘记了这个方法的关键点:初始和最终重命名都必须在主文件的代码块中执行。一个简单的例子:
<强> main.bat 强>
@echo off
echo Calling :test and :hello functions in the library.bat file:
rem Switch the context to the library file
(ren "%~NX0" temp.bat & ren library.bat "%~NX0"
call :test
echo Back from library.bat :test function
call :hello
echo Back from library.bat :hello function
rem Switch the context back to the main file
ren "%~NX0" library.bat & ren temp.bat "%~NX0")
echo Continue in main file
<强> library.bat 强>
:test
echo I am :test function in library.bat file
exit /B
:hello
echo I am :hello function in library.bat file
exit /B
此方法的缺点是,如果在重命名文件时发生运行时错误,则文件仍会重命名,但这可以通过非常简单的方式修复。例如,check.bat文件可能会检查library.bat文件是否存在,如果找不到则会重命名。