Как переименовать несколько изображений с возрастающим целым числом? - PullRequest
1 голос
/ 24 апреля 2020

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

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

1239.jpg => file1.jpg
file.jpg => file2.jpg
image.jpg => file3.jpg

Мои команды, выполненные в окне командной строки для этой задачи:

setlocal EnableDelayedExpansion
set filename=file
set counter=1
for /f "usebackq delims=*" %i in ('dir /b *.jpg') do (set /a counter+=1 ren "%i" "%filename%!counter!.jpg")

Но это приводит к сообщению об ошибке Missing operator.

Кто-нибудь может мне помочь с этим?

1 Ответ

0 голосов
/ 24 апреля 2020

Команды SETLOCAL и ENDLOCAL могут использоваться только в командном файле. Пожалуйста, прочитайте этот ответ для получения подробной информации о командах SETLOCAL и ENDLOCAL . Эти две команды ничего не делают при выполнении в окне командной строки. Необходимо запустить cmd.exe с параметром /V:ON, чтобы использовать отложенное расширение в окне командной строки, как объясняется выводом справки при запуске cmd /? в окне командной строки.

Использование usebackq требует выполнения командной строки в ` вместо ' как обычно. usebackq в основном используется для обработки строк текстового файла, имя которого указано в круглых скобках, заключенных в ".

Следующая командная строка с двумя командами SET и REN не имеет допустимого синтаксиса. Команда SET интерпретирует все после /a как арифметическое c выражение для оценки. В этом случае в выражении отсутствует оператор между 1 и ren, в результате чего ren будет интерпретироваться здесь как имя переменной среды, а не как команда, которая будет выполнена после set.

(set /a counter+=1 ren "%i" "%filename%!counter!.jpg")

Допустимая командная строка:

set /A "counter+=1" & ren "%i" "%filename%!counter!.jpg"

Заключение арифметического c выражения в двойные кавычки проясняет для команды SET , где начинается арифметическое c выражение и где оно концы. Оператор условного выполнения & интерпретируется командным процессором Windows перед выполнением команды SET и приводит к выполнению команды REN после команды SET даже при включении SET не сможет оценить арифметическое c выражение.

Задача переименования файла, выполняемая с помощью командного процессора Windows, будет нелегко выполнить, если

  1. расширение файлов не должно изменяться, и
  2. файлы с любым именем, включая файлы с одним или несколькими &()[]{}^=;!'+,`~, должны поддерживаться, и
  3. в каталоге уже могут быть файлы с одним из новые имена файлов.

Для тестирования приведенного ниже пакетного файла я сначала создал в каталоге следующие файлы:

file.jpg
file1.jpg
file2.jpg
file3.jpg
file 4.jpg
File8.jpg
hello!.jpg
image.jpg

Каталог находился на диске FAT32. Файловые системы FAT16, FAT32 и exFAT возвращают список совпадающих записей каталога, не отсортированных по имени, как NTFS, что означает вывод списка командой DIR в основной FOR l oop в приведенный ниже код находится в несортированном и, следовательно, непредсказуемом порядке.

Конечно, можно добавить параметр DIR /ON, чтобы получить список имен файлов, упорядоченных по DIR в соответствии с именем, но на самом деле это не очень помогает в этом случае, особенно из-за того, что DIR делает строгую алфавитную сортировку, а не сортировку alphanumeri c.

A строгая сортировка по алфавиту c возвращает список из десяти имен файлов как file1.jpg, file10.jpg, file2.jpg, file3.jpg, ..., file9.jpg, а сортировка по алфавиту c возвращает список из десяти файлов имена как file1.jpg, file2.jpg, file3.jpg, ..., file9.jpg, file10.jpg.

Итак, вот закомментированный пакетный файл для этой задачи переименования файла:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FileName=file"

rem The user can run this batch file with a folder path in which all *.jpg
rem files should be renamed with an incremented number. Otherwise the
rem directory of the batch file is search for *.jpg files to rename.
if not "%~1" == "" (
    pushd "%~1" || exit /B
) else (
    pushd "%~dp0" || exit /B
)

set "FileCount=0"
set "DelayedLoopCount=0"
set "DelayedRenameCount=0"

rem Remove all existing environment variables in local environment of which
rem name starts with DelayedRename_ whereby the underscore is very important
rem because there is also the environment variable DelayedRenameCount.
for /F "delims==" %%I in ('set DelayedRename_ 2^>nul') do set "%%I="

rem Get a captured list of all *.jpg files in current directory and then
rem rename one file after the other if that is possible on no other file
rem has by chance already the new file name for the current file.
for /F "eol=| delims=" %%I in ('dir *.jpg /A-D /B 2^>nul') do call :RenameFile "%%I"
goto DelayedRenameLoop

:RenameFile
set /A FileCount+=1
set "NewName=%FileName%%FileCount%%~x1"

rem Has the file case-sensitive already the right name?
if %1 == "%NewName%" goto :EOF

rem Is the new file name the same as the current name
rem with exception of the case of one or more letters?
if /I %1 == "%NewName%" (
    echo Rename %1 to "%NewName%"
    ren %1 "%NewName%"
    goto :EOF
)

rem Is there no other file which has already the new name?
if not exist "%NewName%" (
    echo Rename %1 to "%NewName%"
    ren %1 "%NewName%"
    goto :EOF
)

rem Another file or folder has already the new name. Remember the name
rem of this file and the new file name with an environment variable for
rem a delayed rename after all other files have been renamed as far as
rem possible.
set /A DelayedRenameCount+=1
set "DelayedRename_%DelayedRenameCount%=|%~1|%NewName%"
goto :EOF

rem It could happen that "file15.jpg" should be renamed to "file3.jpg"
rem while "file3.jpg" exists already which should be renamed to "file12.jpg"
rem while "file12.jpg" exists already which should be renamed to "file20.jpg".
rem This extra loop is used for such worst case scenarios which is executed
rem in a loop until all files have been renamed with a maximum of 50 loop
rem runs in case of one file cannot be renamed and therefore blocking
rem renaming of another file. An endless running loop should be avoided.
rem A file cannot be renamed if a folder has by chance the new file name.
rem A file cannot be renamed if an application has opened the file with
rem a sharing access mode preventing the rename of the file as long as
rem being opened by this application.

:DelayedRenameLoop
if %DelayedRenameCount% == 0 goto EndBatch
for /F "tokens=1-3 delims=|" %%I in ('set DelayedRename_ 2^>nul') do if not exist "%%K" (
    echo Rename "%%J" to "%%K"
    ren "%%J" "%%K"
    set "%%I"
    set /A DelayedRenameCount-=1
)
set /A DelayedLoopCount+=1
if not %DelayedLoopCount% == 50 goto DelayedRenameLoop

:EndBatch
popd
endlocal

Этот пакетный файл выводится на выполнение:

Rename "file3.jpg" to "file4.jpg"
Rename "file 4.jpg" to "file5.jpg"
Rename "File8.jpg" to "file6.jpg"
Rename "hello!.jpg" to "file7.jpg"
Rename "image.jpg" to "file8.jpg"
Rename "file2.jpg" to "file3.jpg"
Rename "file1.jpg" to "file2.jpg"
Rename "file.jpg" to "file1.jpg"

Файлы в каталоге мы напоследок:

file1.jpg
file2.jpg
file3.jpg
file4.jpg
file5.jpg
file6.jpg
file7.jpg
File8.jpg

А как насчет последнего файла?

У него есть имя файла File8.jpg вместо file8.jpg, хотя выполнено было ren "image.jpg" "file8.jpg". Что ж, FAT32 немного проблематичен c в отношении обновлений таблицы размещения файлов в записи таблицы, которая изменяется только в случае одной или нескольких букв.

Решение состоит в использовании этого пакетного файла с двумя дополнительными FOR зацикливается с # как переменная l oop и оптимизируется путем удаления комментариев.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FileName=file"

if not "%~1" == "" (pushd "%~1" || exit /B) else (pushd "%~dp0" || exit /B)

set "FileCount=0"
set "DelayedLoopCount=0"
set "DelayedRenameCount=0"
for /F "delims==" %%I in ('set DelayedRename_ 2^>nul') do set "%%I="
for /F "eol=| delims=" %%I in ('dir *.jpg /A-D /B 2^>nul') do call :RenameFile "%%I"
goto DelayedRenameLoop

:RenameFile
set /A FileCount+=1
set "NewName=%FileName%%FileCount%%~x1"
if %1 == "%NewName%" goto :EOF
if /I %1 == "%NewName%" (
    echo Rename %1 to "%NewName%"
    ren %1 "%NewName%"
    goto :EOF
)
if not exist "%NewName%" (
    echo Rename %1 to "%NewName%"
    ren %1 "%NewName%"
    for %%# in ("%NewName%") do if not "%%~nx#" == "%NewName%" ren "%%~nx#" "%NewName%"
    goto :EOF
)
set /A DelayedRenameCount+=1
set "DelayedRename_%DelayedRenameCount%=|%~1|%NewName%"
goto :EOF

:DelayedRenameLoop
if %DelayedRenameCount% == 0 goto EndBatch
for /F "tokens=1-3 delims=|" %%I in ('set DelayedRename_ 2^>nul') do if not exist "%%K" (
    echo Rename "%%J" to "%%K"
    ren "%%J" "%%K"
    for %%# in ("%%K") do if not "%%~nx#" == "%%K" ren "%%~nx#" "%%K"
    set "%%I"
    set /A DelayedRenameCount-=1
)
set /A DelayedLoopCount+=1
if not %DelayedLoopCount% == 50 goto DelayedRenameLoop

:EndBatch
popd
endlocal

Результат этого расширенного пакетного файла даже на FAT32:

file1.jpg
file2.jpg
file3.jpg
file4.jpg
file5.jpg
file6.jpg
file7.jpg
file8.jpg

Причина использования | в качестве разделителя строк при выполнении

set "DelayedRename_%DelayedRenameCount%=|%~1|%NewName%"

, приводящего, например, к выполнению

set "DelayedRename_1=|file.jpg|file1.jpg"
set "DelayedRename_2=|file1.jpg|file2.jpg"
set "DelayedRename_3=|file2.jpg|file3.jpg"

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

См. Также документацию Microsoft:

В имени файла допускается знак равенства. Возможно даже, что файл * .jpg имеет в качестве имени файла =My Favorite Picute=.jpg, что является еще одной причиной использования | для выполнения, например

set "DelayedRename_4=|=My Favorite Picute=.jpg|file9.jpg"

, что позже приводит к присвоению DelayedRename_4= l oop переменная I, =My Favorite Picute=.jpg в l oop переменная J и file9.jpg в l oop переменная K в FOR l oop, выполняющем файл с задержкой переименовывает.

Примечание: Каждый FOR l oop с '...' в круглых скобках приводит к

  • в начале в фоновом режиме еще один командный процесс с %ComSpec% /c '...' и
  • захватом выходных данных, записанных для обработки STDOUT , таких как выходные данные cmd.exe внутренних команд DIR и SET
  • пока cmd.exe обрабатывает пакетный файл, ждет, пока не запустится cmd.exe сам завершает работу (закрывается) после выполнения командной строки
  • и затем обрабатывает захваченные строки одну за другой на FOR с игнорированием пустых строк и строк, начинающихся с определенного конца строки ch aracter после выполнения разграничения строк, которое является причиной, по которой eol=| используется на главном FOR l oop, так как имя файла может начинаться с символа конца строки по умолчанию ; и что, конечно, не должно здесь следует игнорировать.

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

Пакетный файл не использует отложенное расширение , поскольку это может вызвать проблемы с именем файла, имеющего один или несколько восклицательных знаков, которые будут интерпретироваться как начало / конец отложенной ссылки на расширенную переменную среды в командной строке, такой как ren "%%J" "%%K". Поэтому для переименования основного файла l oop используется подпрограмма, для которой необходимо получить доступ к двум увеличенным значениям счетчика.

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

  • call /?
  • dir /?
  • echo /?
  • endlocal /?
  • exit /?
  • goto /?
  • if /?
  • popd /?
  • pushd /?
  • rem /?
  • ren /?
  • set /?
  • setlocal /?

Предлагаю дополнительно посмотреть:

...