Можно ли использовать переменную счетчика FOR / L в команде FOR? - PullRequest
2 голосов
/ 04 мая 2019
::for /l %%n in (0, 1, 6) do (

for /F "skip=1 delims=" %%i in (path.txt) do set "dirvar=%%i"&goto nextline
:nextline

for /F "skip=1 delims=" %%i in (file.txt) do set "filevar=%%i"&goto nextline
:nextline

for /F "skip=1 delims=" %%i in (dotonefile.txt) do set "dotvar=%%i"&goto nextline
:nextline

SET dirvar=%dirvar%
SET filevar=%filevar%
SET dotvar=%dotvar%
SET dirfile=%dirvar%%filevar%
SET dirdotfile=%dirvar%%dotvar%

IF EXIST %dirfile% (
    del %dirdotfile%
) ELSE (
    rename %dirdotfile% %dirfile%
)

::)

Мой пакетный скрипт выше работает нормально, так как он запускается один раз.Он читает 2-ю строку из трех отдельных текстовых файлов в переменные.Затем он проверяет, находится ли имя файла в каталоге, и если оно называется IMG001.jpg, оно удаляет IMG001.1.jpg.в том же каталоге.Если IMG001.jpg НЕ найден в каталоге, он переименовывает IMG001.1.jpg в каталоге в IMG001.jpg.

path.txt - это просто текстовый файл со списком путей к папкам, например:

F:\My Pictures\2005-Misc\
F:\My Pictures\2006-Misc\
F:\My Pictures\2007-Misc\

file.txt - это просто текстовый файл со списком имен файлов, где строка 1 - это файл в каталоге, который также является строкой 1 файла path.txt.Таким образом, в папке 2005-Misc может быть IMG001.jpg, в папке 2006-Misc - IMG001.jpg, а в папке 2007-Misc - IMG001.jpg:

IMG001.JPG
IMG001.JPG
IMG001.JPG

Точно так же с dotonefile.txt, это список имен файлов, которые находятся в соответствующем каталоге, указанном в path.txt.Таким образом, в папке 2005-Misc есть файл IMG001.1.jpg, в 2006-м - один, а в 2007-м - один.

IMG001.1.JPG
IMG001.1.JPG
IMG001.1.JPG

Я хочу зациклить этот скрипт и повторить его, чтобы ончитает строки от 1 до n (n может быть жестко запрограммирован, над ним сейчас 7) из текстовых файлов в переменные, затем тестирует и переименовывает для каждого имени файла.

Я попытался раскомментировать первую и последнюю строки, а затемв трех циклах for я заменил жестко запрограммированную «1» на «%% n», но пакетный файл не будет запускаться с ошибкой «синтаксис команды неверен».Ниже моя попытка, которая не работает.Любой совет, как настроить его для запуска?Я пробовал все виды комбинаций создания новой переменной count, которая увеличивается на 1 в конце, используя отложенное расширение в различных формах переменных, ничего не работает.

for /l %%n in (0, 1, 6) do (

for /F "skip=%%n delims=" %%i in (path.txt) do set "dirvar=%%i"&goto nextline
:nextline

for /F "skip=%%n delims=" %%i in (file.txt) do set "filevar=%%i"&goto nextline
:nextline

for /F "skip=%%n delims=" %%i in (dotonefile.txt) do set "dotvar=%%i"&goto nextline
:nextline

SET dirvar=%dirvar%
SET filevar=%filevar%
SET dotvar=%dotvar%
SET dirfile=%dirvar%%filevar%
SET dirdotfile=%dirvar%%dotvar%

IF EXIST %dirfile% (
    del %dirdotfile%
) ELSE (
    rename %dirdotfile% %dirfile%
)

)

1 Ответ

2 голосов
/ 04 мая 2019

Основная проблема заключается в том, что командный процессор Windows cmd.exe не поддерживает метки внутри командных блоков, которые полностью анализируются перед выполнением команды с использованием командного блока.Пожалуйста, прочтите подробности Как синтаксический анализ сценариев интерпретатора команд Windows (CMD.EXE)?

Решения используют подпрограмму.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /L %%N in (0,1,6) do call :ProcessFiles %%N
endlocal
goto :EOF

:ProcessFiles
if not %1 == 0 ( set "SkipOption=skip=%1 " ) else ( set "SkipOption=" )
set "DirVar="
for /F "%SkipOption%eol=| delims=" %%I in (path.txt) do set "DirVar=%%I" & goto GetFileVar
:GetFileVar
set "FileVar="
for /F "%SkipOption%eol=| delims=" %%I in (file.txt) do set "FileVar=%%I" & goto GetDotVar
:GetDotVar
set "DotVar="
for /F "%SkipOption%eol=| delims=" %%I in (dotonefile.txt) do set "DotVar=%%I" & goto CheckFile

:CheckFile
set "DirFile=%DirVar%%FileVar%"
set "DirDotFile=%DirVar%%DotVar%"
if exist "%DirFile%" (
    del "%DirDotFile%"
) else (
    rename "%DirDotFile%" "%DirFile%"
)
goto :EOF

Более разумный подходиспользовать этот код командного файла вообще без использования текстовых файлов.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "eol=| delims=" %%I  in ('dir "F:\My Pictures\*.1.JPG" /A-D /B /S 2^>nul') do (
    for %%J in ("%%~dpnI") do (
        if exist "%%~dpnJ%%~xI" (
            del "%%I"
        ) else (
            ren "%%I" "%%~nJ%%~xI"
        )
    )
)
endlocal

Цикл FOR начинается с %ComSpec% /C еще одного cmd.exe командного процесса в фоновом режиме для выполнения командыстрока:

dir "F:\My Pictures\*.1.JPG" /A-D /B /S 2>nul

DIR выполняет поиск с указанными параметрами для

  • файлов из-за опции /A-D (атрибут не каталог)
  • соответствует регистронезависимому шаблону *.1.JPG
  • в каталоге F:\My Pictures и всех его подкаталогах из-за опции /S
  • и выводит в голом формате из-заопция /B просто
  • имя файла с расширением файла и полным путем из-за опции /S.

DIR выдаст сообщение об ошибке в случаени один файл не может быть найден во всем дереве каталогов, соответствующих этимEria.Это сообщение об ошибке подавляется путем перенаправления его на устройство NUL .

. Прочтите статью Microsoft о Использование операторов перенаправления команд для объяснения 2>nul.Оператор перенаправления > должен быть экранирован с помощью символа вставки ^ в командной строке FOR , чтобы интерпретироваться как литеральный символ, когда интерпретатор команд Windows обрабатывает эту командную строку перед выполнением команды FOR , котораявыполняет встроенную командную строку dir в отдельном командном процессе, запущенном в фоновом режиме.

FOR захватывает все выходные данные для обработки STDOUT запущенного командного процесса и обрабатывает захваченныйтекст построчно после начала cmd.exe закончено.

FOR игнорирует пустые строки, которые здесь вообще не встречаются. FOR также будет игнорировать строки, начинающиеся с ;, потому что это опция по умолчанию для конца строки.Поскольку DIR выводит имена файлов с полным путем, невозможно, чтобы строка начиналась с ;.Но eol=|, тем не менее, используется для определения вертикальной черты как конца строки, который никогда не может содержать имя папки / файла.

FOR по умолчанию разбивает каждую строку на подстроки (токены)использование нормального пробела и символа горизонтальной табуляции в качестве разделителей.Такое поведение здесь нежелательно, поскольку путь к файлу может содержать символ пробела.По этой причине delims= используется для определения пустого списка разделителей, который отключает разделение строк.

Внутренний FOR используется для присвоения переменной цикла J толькострока, оставленная до .1.JPG.

Условие IF проверяет, существует ли уже файл *.JPG для текущего файла *.1.JPG в том же каталоге, что и текущий файл, и в этом случае файл *.1.JPG удаляется или иным образом переименовывается в *.JPG, если эта операция удаления или переименования файла вообще разрешена в зависимости от атрибута только для чтения, прав доступа к файлам для текущей учетной записи и текущих прав доступа к файлу.

Нодавайте предположим, что имена файлов изображений могут быть любыми именами файлов, соответствующими *.jpg, и могут быть не только *.1.jpg, но также файлы изображений *.2.jpg до *.99.jpg, то есть любое число после точки перед расширением файла .jpg,В этом случае DIR недостаточно для получения списка имен файлов с расширением и полным путем.Дополнительно необходимо использовать FINDSTR с регулярным выражением для фильтрации списка имен файлов.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "eol=| delims=" %%I  in ('dir "F:\My Pictures\*.*.jpg" /A-D /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /R "\.[0123456789][0123456789]*\.jpg$"') do (
    for %%J in ("%%~dpnI") do (
        if exist "%%~dpnJ%%~xI" (
            del "%%I"
        ) else (
            ren "%%I" "%%~nJ%%~xI"
        )
    )
)
endlocal

First FINDSTR выводит только строки, прочитанные из STDIN который

  • совпадает с учетом регистра из-за опции /I
  • регулярного выражения \.[0123456789][0123456789]*\.jpg$
  • , как явно объявлено с опцией /R.

Регулярное выражение соответствует строке, состоящей из точки, одной или нескольких цифр, еще одной точки и строки jpg, найденной в конце строки.Таким образом, имя файла, например Hello.World.jpg, выводимое DIR , не соответствует FINDSTR и, следовательно, не выводится FINDSTR и поэтому не обрабатывается FOR .
Но имя файла, например Hello.World.393.jpg, обрабатывается и либо удаляется, либо переименовывается в Hello.World.jpg в зависимости от наличия Hello.World.jpg в том же каталоге.

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

  • call /?
  • del /?
  • dir /?
  • echo /?
  • endlocal /?
  • findstr /?
  • for /?
  • goto /?
  • if /?
  • ren /? или rename /?
  • set /?
  • setlocal /?

См. Также Куда возвращается GOTO: EOF?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...