12

我试图弄清楚 file1.bat 如何在指定的标签处调用 file2.bat。

我想我可以这样做:

文件1.bat

:config
@echo off
:setvars
set labelmarker=labelmarker
call file2.bat
pause > nul
:EOF

文件2.bat

if %labelmarker%==labelmarker goto label4
:label1
echo it won't work...
goto EOF
:label2
echo it must work!
goto EOF
:label3
echo it didn't work...
goto EOF
:label4
echo it works!
goto EOF
:EOF

这行得通。但我想从 file1.bat 中调用一个蝙蝠和标签。是否可以使用控制字符或ascii代码或任何东西?就像我试过的

call file2.bat | goto label4 - doesn't work
call file2.bat > goto label4 - doesn't work
call file2.bat @label4 - doesn't work

任何帮助将不胜感激。

即使它涉及将特定标签和内容提取到新文件中也可以。

4

5 回答 5

9

您可以将要转到的标签作为参数传递

示例脚本

第一个.bat

@echo off
set label=GOHERE
call Second.bat %label%
pause >nul

二.bat

@echo off
goto %1
echo This line should be skipped
:GOHERE
echo Jumped here
于 2012-07-20T09:17:40.930 回答
8

你可以使用一个奇怪的技巧
您可以转到第二批中的标签,而无需在第二批中调用它!

第一个.bat

@echo off
call :label
echo returned
exit /b

:label
second.bat
exit /b

二.bat

@echo off
echo Main of second.bat
exit /b

:label
echo This is second.bat at LABEL
exit /b

输出

This is second.bat at LABEL
returned

似乎没有原因为什么调用标签,也没有为什么控件应该返回到first.bat,因为第二批在没有CALL的情况下被调用。 第一点的原因似乎是命令的内部代码。 第二点可以解释,因为在第一个批处理文件中的虚拟标签之前有一个调用。 在second.bat 中直接返回调用(第 3 行)而不是第 7 行的调用
goto

exit /bfirst.batsecond.bat

编辑:如何禁用奇怪的行为

如果您在其中附加命令,second.bat它将不再隐式跳转到second.bat中的标签。

second.bat & rem将输出更改为 OUTPUT

Main of second.bat
returned
于 2012-07-20T09:42:03.237 回答
3

有几种方法或技巧可以做到这一点。在这个解决方案中,诀窍在于将正在运行的程序的上下文更改为第二个批处理文件。在此更改之后,第二个批处理文件中的所有标签都成为正在运行的程序的本地标签,因此可以通过通常的call :label命令直接调用它们,也可以以完全标准的方式包含参数。运行程序的上下文必须在程序终止之前恢复。

更改上下文组成的方法是第二个批处理文件重命名为与第一个相同的名称(并将第一个重命名为任何其他名称),因此当批处理文件处理器查找标签时,它实际上会搜索内容第二个文件!在程序终止之前,必须将文件重命名回其原始名称。使该方法起作用的关键在于,两组重命名命令(以及它们之间的所有代码)都必须用括号括起来;这样,代码是先解析后从内存中执行的,所以磁盘上文件的重命名不影响它。当然,这意味着对代码中所有变量的值的访问必须通过延迟!扩展!(或使用call %%variable%%技巧)。

第一个.bat

@echo off

rem Change the running context to the second/library batch file:
(
ren first.bat temporary.bat
ren second.bat first.bat

rem From this point on, you may call any label in second.bat like if it was a local label

call :label2
echo Returned from :label2
call :label1
echo Returned from :label1

rem Recover the running context to the original batch file
ren first.bat second.bat
ren temporary.bat first.bat
)

echo This is first.bat ending...
pause > nul

二.bat

@echo off

:label1
echo I am label1 subroutine at second.bat
goto :EOF

:label2
echo This is the second subroutine at second.bat
goto :EOF

输出

This is the second subroutine at second.bat
Returned from :label2
I am label1 subroutine at second.bat
Returned from :label1
This is first.bat ending...

您应该注意,此方法允许以通常的方式开发第一个文件中的子例程(无需更改上下文),然后只需将完成的子例程移动到第二个/库文件,因为调用它们的方式完全相同两种情况。这种方法不需要对第二个/库文件进行任何更改,也不需要对子程序的调用方式进行任何更改;它只需要在第一个文件中插入两个小块的重命名命令。


编辑发生运行时错误时恢复文件

如评论中所述,如果在重命名文件后发生运行时错误,则不会将文件重命名回其原始名称;但是,通过 second.bat 文件的存在很容易检测到这种情况,如果这样的文件不存在,则恢复文件。这个测试可以在一个在单独的 cmd.exe 上下文中运行原始代码的主管部分中完成,因此即使原始代码因错误而取消,该部分也将始终正确完成。

第一个.bat

@echo off

if "%~1" equ "Original" goto Original

rem This supervisor section run the original code in a separate cmd.exe context
rem and restore the files if an error happened in the original code
(
cmd /C "%~F0" Original
if not exist second.bat (
   echo Error detected!  Restoring files
   ren first.bat second.bat & ren temporary.bat first.bat
)
goto :EOF
)


:Original

( ren first.bat temporary.bat & ren second.bat first.bat

call :label1
echo Returned from :label1
call :label2
echo Returned from :label2

ren first.bat second.bat & ren temporary.bat first.bat )

echo This is first.bat ending...

二.bat

@echo off

:label1
echo I am label1 subroutine at second.bat
exit /B

:label2
set "var="
if %var% equ X echo This line cause a run-time error!
exit /B

输出

I am label1 subroutine at second.bat
Returned from :label1
No se esperaba X en este momento.
Error detected!  Restoring files
于 2017-05-01T15:23:25.243 回答
1

我刚刚创建了一个可能对您有用的脚本。我认为它的优势在于您不必以任何方式修改被调用的脚本。我敢肯定,只要花一点时间,您就可以完善它并使其符合您的目的。我还可以认为,当调用的脚本很大时,它对于生产使用的速度不够快。此方法包括将我的脚本放置到您自己的脚本的文件夹中,并像这样使用它:

编辑

现在这个脚本可以在任何目录下工作,并且可以使用被调用脚本的完整或相对路径输入,有或没有文件扩展名(C:\scripts\script、C:\scripts\script.bat、.\scripts\script.bat)。 cmd等)

用法:

给定一个示例脚本script.bat

:LABEL_1
ECHO This is label number one!
GOTO :EOF

:LABEL_2
ECHO This is label number two!
GOTO :EOF

以下输入:

CALLAT script :LABEL_2

应该输出:

This is label number two!

CALLAT.bat的源代码:

@ECHO OFF
SETLOCAL EnableDelayedExpansion
@ECHO OFF

rem Create a folder in the temporary files directory
MKDIR "%TEMP%\CALLAT\"> NUL

rem Chose a name for a temporal script
SET TEMP_SCRIPT="%TEMP%\CALLAT\temp-script.bat"

rem Get the full path to the called script
FOR /F "delims=" %%F IN ('DIR /B /S "%1*" 2^>NUL') DO SET ORIGINAL_SCRIPT=%%F

rem Add this lines to go directly to the desired label in the temp script
ECHO @ECHO OFF> %TEMP_SCRIPT%
ECHO GOTO %2>> %TEMP_SCRIPT%

rem Concatenate the called script to the end of the temp script
COPY /B %TEMP_SCRIPT%+%ORIGINAL_SCRIPT% %TEMP_SCRIPT%>NUL

rem Call the modified script
CALL %TEMP_SCRIPT%

rem Clean up
RD "%TEMP%\CALLAT\" /S /Q>NUL

ENDLOCAL
于 2017-05-08T03:03:51.920 回答
0

正如我在附在答案中的评论中所说,我授予了赏金,因为@NicoBerrogorry 花时间设计了一个出色的解决方案,并提供了完整的文章。

然而,他忽略了一个语法错误,可能是因为他不使用CMD文件,而我几乎完全放弃了BAT文件。以下 CALLAT 脚本包含一项更正和四项增强功能。

  1. 它处理完全指定的命令,即指定文件名及其扩展名的命令。
  2. 它纠正了导致它忽略CMD文件的原始疏忽。
  3. 当根本找不到目标文件时,它会显示一条错误消息。
  4. 一次添加一行文件的for循环被一个绝对老式的COPY命令替换,该命令将目标脚本文件附加到两行前导码中,使整个工作正常。如果您忘记或不知道它, 复制命令末尾的> NUL:会丢弃“已复制 1 个文件”消息。
  5. 虽然原版完成了它的使命,但它并没有自行清理;这个版本通过删除临时脚本文件和创建它的临时目录来做到这一点。

@ECHO OFF
SETLOCAL EnableDelayedExpansion

rem Create a folder in the temporary files directory.
IF NOT EXIST "%TEMP%\CALLAT\" MKDIR "%TEMP%\CALLAT\"

rem Chose a name for the modified script.
SET MODIFIED_SCRIPT="%TEMP%\CALLAT\modified_%1.bat"

rem Convert the called script name to the corresponding .bat
rem or .cmd full path to the called script.

rem Then load the script. - 2017/05/08 - DAG - The second if exist test duplicated the first. Instead, it must evaluate for the .CMD extension.

SET "COMMAND_FILE=%~dp0%1"
IF EXIST "%COMMAND_FILE%.bat" (
    SET "COMMAND_FILE=%COMMAND_FILE%.bat"
) ELSE IF EXIST "%COMMAND_FILE%.cmd" (
    SET "COMMAND_FILE=%COMMAND_FILE%.cmd"
) else if exist "%COMMAND_FILE%" (
	echo INFO: Using "%COMMAND_FILE%"
) else (
	echo ERROR: Cannot find script file %COMMAND_FILE%.bat
	echo                             or %COMMAND_FILE%.cmd
)

rem Add some lines to go directly to the desired label.
ECHO @ECHO OFF> %MODIFIED_SCRIPT%
ECHO GOTO %2>> %MODIFIED_SCRIPT%

rem Append the called script.
copy %MODIFIED_SCRIPT%+%COMMAND_FILE% %MODIFIED_SCRIPT% > NUL:

rem Call the modified script.
CALL %MODIFIED_SCRIPT%

rem Pack out your trash. When a script ends, you get an ENDLOCAL for free.
del %MODIFIED_SCRIPT%
rd "%TEMP%\CALLAT\"

最后,这个版本的CALLAT消除了多余的ECHO OFF和结束语ENDLOCAL,我很久以前就发现这是不必要的,因为退出脚本意味着ENDLOCAL

由于实际上我的所有生产脚本都位于一个可通过 PATH 目录列表访问的目录中,因此两个脚本位于同一目录中的要求并不是一个重大障碍。此外,只要多做一点工作,几乎肯定可以放松。我将把它作为练习留给感兴趣的读者,但我会给你一个线索;它可能涉及调用一个内部子程序,该子程序可以通过利用[命令行参数]中描述的技术来解析输入文件的名称。1

上面显示的脚本即将投入生产。

于 2017-05-08T20:19:46.960 回答