Переменная ведет себя странно в этом простом пакетном скрипте

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

:: 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".

Внутри циклов for не может быть меток. Вам придется реструктурировать весь сценарий.

SomethingDark 11.08.2024 19:47

@SomethingDark ну, каким-то образом это работает для всего остального, кроме этих временных файлов. У меня был отдельный вопрос о том, как пропустить что-то в цикле for, и было сказано, что метки работают внутри цикла for, но чтобы она работала, после метки должна быть команда (для этого есть rem) , эхо существует только для целей отладки

Bricktop 11.08.2024 19:56

Это работает, потому что goto не срабатывает, если нет временных файлов. Ярлык сам по себе хорош, поскольку это всего лишь маркер «вы здесь», который на самом деле ничего не делает. Кроме того, я только что просмотрел все вопросы, которые вы здесь задали, и ни один из них не дает вам кода, у которого есть переход и соответствующая метка внутри одного и того же набора круглых скобок. Я не знаю, откуда у вас такая идея, но она ошибочна.

SomethingDark 11.08.2024 20:11
superuser.com/questions/1832662/… Я открыт для альтернатив, но мне нравится этот метод за простоту. Очевидно, мне пришлось бы реструктурировать, если бы метка была проблемой, но это кажется маловероятным, поскольку все остальные варианты использования метки работают очень хорошо.
Bricktop 11.08.2024 20:25

Вы взяли это из той части ответа, в которой прямо говорится: «Это не работает?»

SomethingDark 11.08.2024 20:47

Метки внутри блока кода проблематичны (вы использовали трюк, чтобы обойти неожиданное поведение, поэтому эта метка не вызывает проблем), но реальная проблема заключается в том, что каждый goto немедленно разрывает (завершает) конструкцию блока:

Stephan 11.08.2024 20:49
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
6
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В этом пакетном файле нет меток, которые не работают внутри командного блока, начинающегося с ( и заканчивающегося соответствующим ), поскольку весь командный блок сначала анализируется перед выполнением любой командной строки, включая командную строку 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 /?

Другие вопросы по теме