Пакетный файл, как вызвать другой пакетный файл по указанной метке или вызову и сразу же перейти к определенной метке?
Я пытаюсь выяснить, как файл 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\"