Изменение командного файла при его запуске - PullRequest
33 голосов
/ 25 мая 2009

Я запускаю долго работающий пакетный файл. Теперь я понимаю, что мне нужно добавить еще несколько команд в конце командного файла (никаких изменений в существующем контенте, только некоторые дополнительные команды). Возможно ли это сделать, учитывая, что большинство командных файлов читаются постепенно и выполняются один за другим? Или система читает все содержимое файла и затем запускает задание?

Ответы [ 6 ]

32 голосов
/ 25 мая 2009

Я только что попробовал, и, несмотря на мою интуицию, в конце он подобрал новые команды (в Windows XP)

Я создал командный файл, содержащий

echo Hello
pause
echo world

Я запустил файл и, пока он был приостановлен, добавил

echo Salute

Сохранил его и нажал клавишу ввода, чтобы ограничить паузу, все три подсказки были выведены на консоль.

Итак, дерзайте!

21 голосов
/ 25 мая 2009

Интерпретатор команд запоминает положение строки в командном файле. Пока вы изменяете командный файл после текущей позиции исполняемой строки, все будет в порядке.

Если вы измените его раньше, он начнет делать странные вещи (повторять команды и т. Д.).

8 голосов
/ 11 марта 2012

Пример Джеба очень интересный, но очень сильно зависит от длины добавляемого или удаляемого текста. Я думаю, что нелогичные результаты - это то, что имел в виду Обман, когда он сказал: «Если вы измените его раньше, он начнет делать странные вещи (повторять команды и т. Д.)».

Я изменил код jeb, чтобы показать, как динамический код различной длины можно свободно модифицировать в начале исполняемого пакетного файла, пока имеется соответствующее заполнение. Весь динамический раздел полностью заменяется каждой итерацией. Каждая динамическая строка имеет префикс без помех ;. Это удобно для FOR /F удаления динамического кода из-за неявной опции EOL=;.

Вместо того, чтобы искать конкретный номер строки, я ищу конкретный комментарий, чтобы определить, где начинается динамический код. Это легче поддерживать.

Я использую строки знаков равенства для безвредного заполнения кода для расширения и сжатия. Можно использовать любую комбинацию следующих символов: запятая, точка с запятой, равно, пробел, табуляция и / или символ новой строки. (Конечно, заполнение не может начинаться с точки с запятой.) Знаки равенства в скобках позволяют расширять код. Знаки равенства после скобок допускают сжатие кода.

Обратите внимание, что FOR /F убирает пустые строки. Это ограничение может быть преодолено с помощью FINDSTR, чтобы префикс каждой строки с номером строки, а затем вырезать префикс в цикле. Но дополнительный код замедляет работу, поэтому делать это не стоит, если код не зависит от пустых строк.

@echo off
setlocal DisableDelayedExpansion
echo The starting filesize is %~z0
:loop
echo ----------------------
::*** Start of dynamic code ***
;set value=1
::*** End of dynamic code ***
echo The current value=%value%
::
::The 2 lines of equal signs amount to 164 bytes, including end of line chars.
::Putting the lines both within and after the parentheses allows for expansion
::or contraction by up to 164 bytes within the dynamic section of code.
(
  call :changeBatch
  ==============================================================================
  ==============================================================================
)
================================================================================
================================================================================
set /p "quit=Enter Q to quit, anything else to continue: "
if /i "%quit%"=="Q" exit /b
goto :loop
:changeBatch
(
  for /f "usebackq delims=" %%a in ("%~f0") do (
    echo %%a
    if "%%a"=="::*** Start of dynamic code ***" (
      setlocal enableDelayedExpansion
      set /a newValue=value+1, extra=!random!%%9
      echo ;set value=!newValue!
      for /l %%n in (1 1 !extra!) do echo ;echo extra line %%n
      endlocal
    )
  )
) >"%~f0.tmp"
::
::The 2 lines of equal signs amount to 164 bytes, including end of line chars.
::Putting the lines both within and after the parentheses allows for expansion
::or contraction by up to 164 bytes within the dynamic section of code.
(
  move /y "%~f0.tmp" "%~f0" > nul
  ==============================================================================
  ==============================================================================
)
================================================================================
================================================================================
echo The new filesize is %~z0
exit /b

Вышеописанное работает, но все намного проще, если динамический код перемещается в подпрограмму в конце файла. Код может расширяться и сокращаться без ограничений и без необходимости дополнения. FINDSTR намного быстрее чем FOR / F удаляет динамическую часть. Динамические строки можно смело ставить перед точкой с запятой (включая метки!). Затем опция FINDSTR / V используется для исключения строк, начинающихся с точки с запятой, и новый динамический код можно просто добавить.

@echo off
setlocal DisableDelayedExpansion
echo The starting filesize is %~z0

:loop
echo ----------------------
call :dynamicCode1
call :dynamicCode2
echo The current value=%value%
call :changeBatch
set /p "quit=Enter Q to quit, anything else to continue: "
if /i "%quit%"=="Q" exit /b
goto :loop

:changeBatch
(
  findstr /v "^;" "%~f0"
  setlocal enableDelayedExpansion
  set /a newValue=value+1, extra=!random!%%9
  echo ;:dynamicCode1
  echo ;set value=!newValue!
  echo ;exit /b
  echo ;
  echo ;:dynamicCode2
  for /l %%n in (1 1 !extra!) do echo ;echo extra line %%n
  echo ;exit /b
  endlocal
) >"%~f0.tmp"
move /y "%~f0.tmp" "%~f0" > nul
echo The new filesize is %~z0
exit /b

;:dynamicCode1
;set value=33
;exit /b
;
;:dynamicCode2
;echo extra line 1
;exit /b
5 голосов
/ 30 декабря 2014

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

Много лет назад, до Windows 3, на месте, где я работал, была встроенная система меню в MS-DOS. То, как он запускал вещи, было довольно элегантным: он фактически запускался из пакетного файла, который основная программа (написанная на C) модифицировала для запуска сценариев. Этот трюк означал, что сама программа меню не занимала место в памяти во время выполнения выбора. И это включало такие вещи, как программа LAN Mail и программа терминала 3270.

Но запуск из самоизменяющегося пакетного файла означал, что его сценарии могли также выполнять такие вещи, как загрузка программ TSR, и фактически могли делать практически все, что вы могли бы поместить в пакетный файл. Что сделало его очень мощным. Только команда GOTO не работала, пока автор в конце концов не выяснил, как заставить пакетный файл перезапускаться для каждой команды.

4 голосов
/ 09 марта 2012

Почти как rein сказал, cmd.exe запоминает позицию файла (не только позицию строки), в которой он находится в данный момент, а также при каждом вызове выдвигает позицию файла в невидимом стеке.

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

Небольшой образец самоизменяющейся партии
Это меняет линию set value=1000 непрерывно

@echo off
setlocal DisableDelayedExpansion
:loop
REM **** the next line will be changed
set value=1000
rem ***
echo ----------------------
echo The current value=%value%
<nul set /p ".=Press a key"
pause > nul
echo(
(
call :changeBatch
rem This should be here and it should be long
)
rem ** It is neccessary, that this is also here!
goto :loop
rem ...
:changeBatch
set /a n=0
set /a newValue=value+1
set /a toggle=value %% 2
set "theNewLine=set value=%newValue%"
if %toggle%==0 (
   set "theNewLine=%theNewLine% & rem This adds 50 byte to the filesize.........."
)
del "%~f0.tmp" 2> nul
for /F "usebackq delims=" %%a in ("%~f0") DO (
   set /a n+=1
   set "line=%%a"
   setlocal EnableDelayedExpansion
   if !n!==5 (
       (echo !theNewLine!)
   ) ELSE (
       (echo !line!)
   )
   endlocal
) >> "%~f0.tmp"
(
  rem the copy should be done in a parenthesis block
  copy "%~f0.tmp" "%~f0" > nul
  if Armageddon==TheEndOfDays (
   echo This can't never be true, or is it?
  )
)
echo The first line after the replace action....
echo The second line comes always after the first line?
echo The current filesize is now %~z0
goto :eof 
3 голосов
/ 07 июля 2015

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

Если после этого запомненного местоположения в файл было внесено изменение, интерпретатор должен продолжить выполнение измененного сценария. Однако, если изменение было сделано до этого момента, и это изменение изменяет длину текста в этом месте (например, вы вставили или удалили какой-то текст), то запоминаемое местоположение больше не относится к началу следующей команды , Когда интерпретатор пытается прочитать следующую «строку», он вместо этого берет другую строку или, возможно, часть строки в зависимости от того, сколько текста было вставлено или удалено. Если вам повезет, он, вероятно, не сможет обработать любое слово, на которое произойдет посадка, выдаст ошибку и продолжит выполнение со следующей строки - но все же, вероятно, не то, что вы хотите.

Однако, понимая, что происходит, вы можете структурировать свои сценарии, чтобы уменьшить риск. У меня есть сценарии, которые реализуют просто систему меню, отображая меню, принимая ввод от пользователя с помощью команды choice и затем обрабатывая выбор. Хитрость заключается в том, чтобы убедиться, что точка, в которой скрипт ожидает ввода, находится в верхней части файла, чтобы любые изменения, которые вы, возможно, захотите внести, произошли после этой точки и не имели неприятных последствий.

Пример:

:top
call :displayMenu
:prompt
REM The script will spend most of its time waiting here.
choice /C:1234 /N "Enter selection: "
if ERRORLEVEL == 4 goto DoOption4
if ERRORLEVEL == 3 goto DoOption3
if ERRORLEVEL == 2 goto DoOption2
goto DoOption1
:displayMenu
(many lines to display menu)
goto prompt
:DoOption1
(many lines to do Option 1)
goto top
:DoOption2
(many lines to do Option 2)
goto top
(etc)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...