我不确定原始问题的上下文,但这可能是切换到带有 VBScript 或 WPS 的 WSH 之类的东西,或除批处理文件之外的任何其他支持控制台的脚本的情况。我会回答最初的问题,但首先.. 一点背景和理解..
DOS 和 Windows 的命令行/控制台模式通常是 COMMAND.COM 或 CMD.EXE,不适合脚本/编程逻辑。相反,它们适用于执行命令和程序,并且批处理文件被添加到常用的命令序列中,以包装在单个类型的命令中。例如,您可能有一个旧的 DOS 游戏,每次都需要以下命令,因此将其打包为批处理文件:
@EHO OFF
@REM Load the VESA driver fix..
VESAFIX.EXE
@REM Load the joystick driver..
JOYSTICK.COM
@REM Now run the game
RUNGAME.EXE
许多人倾向于将整个批处理文件视为一个原子单元——但事实并非如此。每次运行批处理文件时,命令解释器(COMMAND.COM 或 CMD.EXE)只会像您手动键入这些行一样。它确实没有像常规编程/脚本语言那样的词汇和范围界定的坚实概念——也就是说,它不会像调用堆栈等那样维护太多额外的元数据。它所维护的东西更像是事后的想法,而不是从一开始就内置到批处理文件中。
然而,一旦你改变思维方式,你通常可以使用各种技巧和技术来模拟更强大的脚本/编程语言来克服这个限制;但是您仍然必须记住,无论如何,批处理文件仍然会受到限制。
无论如何,使用批处理文件库的一种技术是创建一个批处理文件,其中第一个参数用于指示正在调用哪个函数:
CALL BATLIB.BAT FunctionName Parameter1 Parameter2 ...
当考虑到这一点编写库时,这已经足够好用了,所以它会知道跳过第一个参数等等。
在 Windows 系统中使用更现代的 CMD.EXE 版本允许在 CALL 语法中使用“:labels”,如果您想限制参数范围(它允许您将 %* 用于“所有参数” ,例如),像这样:
CALL :LABEL Parameter1 Paramater2 ...
(来自同一个批处理文件或...)
CALL BATLIB.BAT :LABEL Parameter1 Parameter2 ...
不过,关于这一点的一些注意事项.. 在第一种形式中, :LABEL 必须已经在当前批处理文件中。它将在 CMD.EXE 中创建一个新的“批处理上下文”,其中 %*、%1、%2 等与参数匹配。但是您还必须提供某种返回/退出逻辑来从该上下文返回/退出到调用上下文。
在第二种形式中,CMD.EXE 并没有真正识别出您正在向它传递一个标签,因此您的批处理文件库将不得不期待它并处理它:
@ECHO OFF
CALL %*
这是因为命令解释器在尝试解析 CALL 命令之前替换了 %*,因此在变量扩展之后,CALL 命令会看到 :LABEL 就好像它是硬编码的一样。这也会造成 CMD.EXE 创建另一个批处理上下文的情况,因此您必须确保从该上下文返回/退出两次:一次用于当前库上下文,再次返回原始 CALL。
还有其他方法可以做一个批处理文件库,混合和匹配上述技术,或者使用更复杂的逻辑,使用 GOTO 等等。这实际上是一个如此复杂的话题,以至于有很多关于这个话题的书籍,比我想在这里输入一个简单的答案要多得多!
到目前为止,我几乎忽略了您会遇到的其他问题:如果 CALL 标签不存在怎么办?将如何处理?环境变量扩展呢?什么时候发生?如何防止它过早发生?在参数/参数中使用特殊的 DOS 字符怎么样?例如,解释器如何看到如下行:CALL :ProcessPath %PATH%?(答案是 CMD.EXE _在处理 CALL 命令之前替换了整个% PATH% Windows 的 %PATH% 变量确实如此.. C:\Program Files.. 例如..)
正如你所看到的,事情很快变得复杂和混乱。你必须停止像程序员一样思考,开始像 COMMAND.COM/CMD.EXE 那样思考,它几乎一次只能看到一行,而不是整个批处理文件作为一个原子单元。事实上,这里有一个例子可以帮助你真正掌握它的工作方式。
创建一个文件夹 C:\testing,并将以下批处理文件“oops.bat”放入其中:
@ECHO OFF
ECHO Look mom, no brain!
PAUSE
ECHO Bye mom!
现在打开一个控制台窗口并运行它,但让它在 PAUSE 时停在那里:
C:\testing>oops.bat
Look mom, no brain!
Press any key to continue . . .
当它处于暂停状态时,在文本编辑器中打开 oops.bat 并将其更改为:
@ECHO OFF
ECHO Look mom, no brain!?
ECHO Oops!
PAUSE
ECHO Bye mom!
保存它,然后切换回控制台窗口并按任意键继续运行批处理文件:
'ops!' is not recognized as an internal or external command,
operable program or batch file.
Press any key to continue . . .
Bye mom!
c:\testing>
哇……看到那个错误了吗?发生这种情况是因为我们在 CMD.EXE 仍在运行批处理文件时对其进行了编辑,但是我们的编辑更改了 CMD.COM 认为的批处理文件中的位置。在内部,CMD.EXE 维护一个文件指针,该指针指示下一个要处理的字符的开始,在这种情况下,它应该是带有 PAUSE(和 CRLF)的行之后的字节。但是当我们编辑它时,它改变了批处理文件中下一条命令的位置,但 CMD.EXE 的指针仍然在原来的位置。在这种情况下,它指向“ECHO Oops!”中间的字节位置。行,所以它试图处理“操作!” 作为暂停后的命令。
我希望这清楚地表明 COMMAND.COM/CMD.EXE 将始终将您的批处理文件视为字节流,而不是像脚本语言或编译器那样的逻辑块、子例程等。这就是批处理文件库如此有限的原因。这使得无法将库“导入”到当前正在运行的批处理文件中。
哦,我刚刚有了另一个想法。在现代 Windows 的 CMD.EXE 中,您始终可以创建一个批处理文件,该文件会即时创建一个临时批处理文件,然后调用它:
@ECHO OFF
SET TEMPBAT=%TEMP%\TMP%RANDOM:~0,1%%RANDOM:~0,1%%RANDOM:~0,1%%RANDOM:~0,1%.BAT
ECHO @ECHO OFF > %TEMPBAT%
ECHO ECHO Hi Mom! I'm %TEMPBAT%! >> %TEMPBAT%
ECHO Hello, world, I'm %~dpnx0!
CALL %TEMPBAT%
DEL %TEMPBAT%
这有效地在您的临时目录中创建了一个临时批处理文件,名为 TMP####.BAT(其中 # 被随机数替换;%RANDOM:~0,1% 表示取返回数字的第一个数字by %RANDOM%——我们只需要一个数字,而不是 RANDOM 返回的完整数字..),然后是 ECHO 的“Hello, World”,然后是它自己的全名(%~dpnx0 部分),调用临时批处理文件,这反过来又是 ECHO 的“Hi Mom!” 后跟它自己的 [随机] 名称,然后返回到原始批处理文件,以便它可以进行任何需要的清理,例如在这种情况下删除临时批处理文件。
无论如何,从这篇文章的长度可以看出,这个话题确实不是一个简单的话题。网上有几十个或更多的网页,其中包含大量的批处理文件提示、技巧等,其中许多深入介绍了如何使用它们、创建批处理文件库、注意什么、如何通过引用参数与值参数,如何管理变量何时何地被扩展,等等。
在 Google 上快速搜索“BATCH FILE PROGRAMMING”以找到其中的许多,您还可以查看 Wiki 和 WikiBooks、SS64.com、robvanderwoude.com 甚至 DMOZ 的http://www.dmoz.org/Computers/Software /Operating_Systems/x86/DOS/Programming/Languages/Batch/具有更多资源的目录。
祝你好运!