Пакетный файл, как вызвать другой пакетный файл по указанной метке или вызову и сразу же перейти к определенной метке?

Я пытаюсь выяснить, как файл file1.bat может вызывать файл2.bat на указанной метке.

Я решил, что могу сделать это вот так:

File1.bat

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

File2.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

Это работает. но я хочу назвать bat и ярлык из файла 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

Любая помощь будет принята с благодарностью.

Даже если это связано с извлечением определенной метки и содержимого в новый файл, будет нормально.

Ответ 1

Вы можете передать метку, в которую хотите перейти, в качестве параметра

Примеры скриптов

First.bat

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

Second.bat

@echo off
goto %1
echo This line should be skipped
:GOHERE
echo Jumped here

Ответ 2

Вы можете использовать странный трюк!
Вы можете получить метку во вторичной партии без вызова ее во вторичной партии!

First.bat

@echo off
call :label
echo returned
exit /b

:label
second.bat
exit /b

Second.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.
Причиной для первой точки является внутренний код команды goto.
Вторая точка может быть объяснена, так как есть один вызов до фиктивной метки в первом командном файле.
exit /b в second.bat возвращается непосредственно к вызову (строка 3) first.bat не к вызову second.bat в строке 7

EDIT: Как отключить нечетное поведение

если вы добавите команду в second.bat, она больше не будет скрывать переход к метке в файле second.bat.

second.bat & rem изменит вывод на OUTPUT

Main of second.bat
returned

Ответ 3

Существует несколько методов или трюков, которые позволяют это сделать. В этом решении трюк заключается в изменении контекста текущей программы на второй пакетный файл. После этого изменения все метки во втором командном файле становятся локальными метками запущенной программы, поэтому они могут быть вызваны непосредственно с помощью обычной команды call :label, которая также может включать аргументы полностью стандартным образом. Контекст запущенной программы должен быть восстановлен до завершения программы.

Способ изменения контекста состоит в том, чтобы просто переименовать второй пакетный файл с тем же именем первого (и переименовать первое в другое имя), поэтому, когда процессор пакетного файла ищет метку, он действительно ищет содержимое второго файла! Перед завершением программы файлы должны быть переименованы в исходные имена. Ключевым моментом, который делает этот метод, является то, что оба набора команд переименования (и весь код между ними) должны быть заключены в круглые скобки; таким образом, код сначала разбирается, а затем выполняется из памяти, поэтому переименование файлов на диске не влияет на него. Конечно, эта точка означает, что доступ к значениям всех переменных в коде должен выполняться с помощью отложенного! Расширения! (или используя трюк call %%variable%%).

First.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

Second.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...

Следует отметить, что этот метод позволяет обычным образом разрабатывать подпрограммы в первом файле (без изменения контекста), а затем просто переместить завершенные подпрограммы во второй/библиотечный файл, так как способ их вызова точно то же самое в обоих случаях. Этот метод не требует каких-либо изменений во втором/библиотечном файле и способах вызова подпрограмм; ему просто нужно вставить два небольших блока команд переименования в первый файл.


EDIT: восстановление файлов при возникновении ошибки времени выполнения

Как указано в комментарии, если ошибка во время выполнения происходит после переименования файлов, файлы не переименовываются в исходные имена; однако очень легко обнаружить эту ситуацию из-за наличия файла second.bat и восстановить файлы, если такой файл не существует. Этот тест может быть выполнен в секции супервизора, которые запускают исходный код в отдельном контексте cmd.exe, поэтому этот раздел всегда будет корректно завершен, даже если исходный код был отменен с ошибкой.

First.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...

Second.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

Ответ 4

Я только что создал script, который может оказаться полезным для вас. Я считаю, что сила заключается в том, что вам не нужно каким-либо образом модифицировать ваш вызываемый script. Я уверен, что с небольшим количеством времени вы сможете улучшить его и сделать его подходящим для вашей цели. Я также могу понять, что он недостаточно быстрый для производства, когда названный script большой. Этот метод заключается в том, чтобы поместить мой script в папку ваших собственных скриптов и использовать его так:

ИЗМЕНИТЬ

Теперь этот script работает из любого каталога и может быть введен с полными или относительными путями к вызываемому script, с расширением или без него (C:\scripts\script, C:\scripts\script.bat,.\scripts\script.cmd и т.д.)

Использование:

Для примера script 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

Ответ 5

Как я уже сказал в комментарии, который я приложил к моему ответу, я наградил награду, потому что @NicoBerrogorry потратил время на разработку отличного решения и предоставил полную рецензию.

Тем не менее, была одна синтаксическая ошибка, которую он упустил, вероятно, потому, что он не использует файлы CMD, а я почти полностью отказался от файлов BAT. Следующий CALLAT script включает в себя одну коррекцию и четыре улучшения.

  • Он обрабатывает полностью определенные команды, то есть команды, которые указывают имя файла с своим расширением.
  • Он исправляет недосмотр в оригинале, из-за которого он игнорирует файлы CMD.
  • Если целевой файл просто не найден, отображается сообщение об ошибке.
  • Цикл для, который добавляет файл по одной строке за раз, заменяется явно старой командой COPY, которая добавляет целевой файл script к двум -line преамбула, которая заставляет все это работать. Если вы забыли или не знали об этом, NUL: в конце команды копирования отбрасывает сообщение "1 файл скопировано".
  • Пока оригинал выполнил свою миссию, он не очистился после себя; эта версия делает это, удаляя временный файл script и временный каталог, в котором он создан.

@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\"