我不确定原问题的上下文,但这可能是一种情况,可以切换到类似于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视为硬编码。这还会创建另一个批处理上下文的情况,因此您必须确保两次返回/退出该上下文:一次用于当前库上下文,再次返回到原始的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 . . .
在程序处于PAUSE状态时,打开文本编辑器中的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!" 行的中间字节位置,因此它尝试在PAUSE之后将"ops!"作为命令处理。
我希望这让你清楚,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%表示获取%RANDOM%返回的数字的第一个数字 - 我们只需要一个单个数字,在这里不需要RANDOM返回的完整数字..),然后ECHO's "Hello, World,",接着是它自己的全名(%~dpnx0部分),CALLs临时批处理文件,该文件又ECHO's "Hi Mom!",接着是它自己的[随机]名称,然后返回到原始批处理文件,以便进行任何清理工作,例如在这种情况下删除临时批处理文件。
总之,正如您可以从本帖子的长度看出来的那样,这个主题确实不是一个简单的主题。网络上有数十个或更多网页提供大量批处理文件技巧、技巧等信息,其中许多深入探讨如何使用它们、创建批处理文件库、要注意哪些内容、如何按引用而非按值传递参数、如何管理变量何时何地被展开等等。
快速在谷歌上搜索“BATCH FILE PROGRAMMING”,你可以找到很多相关资源,你也可以查看维基百科和维基教科书、SS64.com、robvanderwoude.com,甚至是
DMOZ的目录等网站获取更多资源。
祝好运!