У меня есть этот скрипт, который проверяет, используются ли каталоги, пытаясь переименовать каталог, а также, кроме того, проверяет, содержит ли он какие-либо известные временные файлы. он работает хорошо, за исключением случаев, когда он встречает каталог с указанными временными файлами.
:: open each top dir for inspection and processing
for /d %%r in (*) do (
rem security
cd /d "%target%"
ren "%%r" "%%r(ctest)" || goto skip
ren "%%r(ctest)" "%%r" || goto skip
cd /d "%%r" || goto skip
dir /s *.!qb *.part *.dash* *.tmp >nul 2>nul && cd .. && goto skip
if defined verbose echo importing "%%~nxr"
rem call any scripts in the subdir with this script's own name
for /r "%~dp0%~n0\" %%s in (*.cmd) do call "%%s"
:skip
rem keep this (label can't be last)
echo done with "%%r"
)
каким-то образом после этой строки dir /s *.!qb *.part *.dash* *.tmp >nul 2>nul && cd .. && goto skip
сценарий останавливается, и я получаю вывод done with "%r"
, где каждый второй каталог показывает имя каталога для %%r
, поэтому ожидается done with "directory name"
.
@SomethingDark ну, каким-то образом это работает для всего остального, кроме этих временных файлов. У меня был отдельный вопрос о том, как пропустить что-то в цикле for, и было сказано, что метки работают внутри цикла for, но чтобы она работала, после метки должна быть команда (для этого есть rem) , эхо существует только для целей отладки
Это работает, потому что goto
не срабатывает, если нет временных файлов. Ярлык сам по себе хорош, поскольку это всего лишь маркер «вы здесь», который на самом деле ничего не делает. Кроме того, я только что просмотрел все вопросы, которые вы здесь задали, и ни один из них не дает вам кода, у которого есть переход и соответствующая метка внутри одного и того же набора круглых скобок. Я не знаю, откуда у вас такая идея, но она ошибочна.
Вы взяли это из той части ответа, в которой прямо говорится: «Это не работает?»
Метки внутри блока кода проблематичны (вы использовали трюк, чтобы обойти неожиданное поведение, поэтому эта метка не вызывает проблем), но реальная проблема заключается в том, что каждый goto
немедленно разрывает (завершает) конструкцию блока:
В этом пакетном файле нет меток, которые не работают внутри командного блока, начинающегося с (
и заканчивающегося соответствующим )
, поскольку весь командный блок сначала анализируется перед выполнением любой командной строки, включая командную строку FOR. См.: Как интерпретатор команд Windows (CMD.EXE) анализирует сценарии?
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "BatchName=%~dpn0"
for /D %%G in ("%CD%\*") do (
pushd "%SystemDrive%\"
ren "%%G" "%%~nxG(ctest)"
if not errorlevel 1 (
ren "%%G(ctest)" "%%~nxG"
pushd "%%G"
dir /A-D /S *.!qb *.part *.dash* *.tmp >nul 2>nul
if errorlevel 1 (
if defined verbose echo importing "%%~nxG"
rem call any scripts in the subdir with this script's own name
for /R "%BatchName%\" %%H in (*.cmd) do call "%%H"
)
popd
)
popd
echo done with "%%~nxG"
)
endlocal
Имя пакетного файла с полным путем, но без расширения файла, уже определено в начале пакетного файла. См. причину: По какой причине путь к пакетному файлу, указанный в %~dp0, иногда меняется при смене каталога?
Рассматриваемый пакетный файл работает с текущим рабочим каталогом, который определяется вне пакетного файла процессом, запускающим cmd.exe
для обработки пакетного файла. Таким образом, это может быть любой каталог. Пакетный файл в этом ответе использует %CD%\*
для поиска нескрытых каталогов в текущем рабочем каталоге, что отличается от простого *
. Найденный каталог имеет полный путь, назначенный переменной цикла G
, а не только имя каталога без пути. Здесь это важно, поскольку pushd "%SystemDrive%\"
помещает путь к текущему рабочему каталогу в стек и затем меняет текущий рабочий каталог на корневой каталог системного диска. Полный путь к начальному текущему каталогу с именем текущего каталога процесса необходим внутри цикла FOR для других командных строк.
%CD%
обычно заменяется строкой пути, не заканчивающейся обратной косой чертой. Исключением является то, что текущий каталог является корневым каталогом диска, и в этом случае %CD%
заменяется буквой диска, двоеточием и обратной косой чертой. Однако C:\\*
здесь не проблема благодаря автоматическим исправлениям файлового ввода-вывода Windows, как описано в документации Microsoft об Именовании файлов, путей и пространств имен.
Внутри цикла FOR текущий каталог изменяется на корневой каталог системного диска с помещением текущего рабочего каталога в стек. Я действительно не понимаю причину cd /d "%target%"
с неизвестным определением переменной среды target
. Также можно использовать pushd "%target%"
, если target
определен строкой пути к папке, которая еще не заключена в "
.
Затем пытается переименовать найденный нескрытый подкаталог, добавляя (ctest)
к имени каталога. Если это не удается из-за того, что каталог или любой подкаталог этого каталога или любой файл в этом каталоге или в его подкаталогах используется любым запущенным процессом или из-за отсутствия разрешений, и поэтому код выхода равен 1
, большинство других строк внутри Цикл FOR игнорируется из-за первого условия IF.
При успешном переименовании каталога каталог немедленно переименовывается обратно без повторной проверки, сработало ли это. Это должно работать всегда, иначе результатом будет повреждение структуры каталогов, вызванное пакетным файлом.
Текущий каталог снова изменяется с помощью команды PUSHD now на текущий обрабатываемый подкаталог исходного текущего рабочего каталога.
Выполняется команда DIR для поиска файлов (не каталогов), включая скрытые файлы, которые по умолчанию игнорируются, если не используется опция /A
, соответствующая одному из шаблонов подстановочных знаков во всем дереве каталогов текущего каталога.
Второе условие IF истинно только в том случае, если не удалось найти файл, соответствующий одному из шаблонов подстановочных знаков. В этом случае выполняется внутренняя команда FOR, которая рекурсивно вызывает все командные файлы с именем .cmd
в совершенно другом каталоге с полным путем к командному файлу и с именем командного файла.
Я предполагаю, что опция /R
используется только для получения имен пакетных файлов с полным путем, присвоенным переменной цикла H
, а указанный каталог вообще не содержит подкаталогов. Если мое предположение верно, то в качестве внутренней командной строки FOR можно также использовать:
for %%H in ("%BatchName%\*.cmd") do call "%%H"
Команда POPD выполняется для второго PUSHD, чтобы извлечь из стека путь к последнему загруженному каталогу и временно снова сделать этот каталог текущим каталогом, который является корневым каталогом системного диска.
Последние две командные строки внутри цикла FOR извлекают исходный путь к текущему каталогу из стека и снова делают этот каталог текущим рабочим каталогом перед выводом информационного сообщения, и FOR ищет следующий нескрытый каталог в исходном текущем рабочем каталоге.
Чтобы понять, какие команды используются и как они работают, откройте окно командной строки , выполните там следующие команды и внимательно прочитайте отображаемые страницы справки для каждой команды.
call /?
… для объяснения %~dpn0
… диск + путь + имя аргумента 0 … имя пакетного файла с полным путем, но без расширения файла.cmd /?
dir /?
echo /?
endlocal /?
for /?
if /?
popd /?
pushd /?
rem /?
ren /?
set /?
… для объяснения динамической переменной CD
setlocal /?
Внутри циклов
for
не может быть меток. Вам придется реструктурировать весь сценарий.