Попробуйте этот код командного файла:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceDir=C:\Development\test"
set "DestDir=C:\Development\test"
for /F "eol=| delims=" %%A in ('dir /B /A-D-H "%SourceDir%\TTT*_*" 2^>nul') do (
for /F "eol=| tokens=1 delims=_" %%B in ("%%~nA") do (
md "%DestDir%\%%B" 2>nul
move /Y "%SourceDir%\%%A" "%DestDir%\%%B\"
)
)
endlocal
Первый FOR выполняется в отдельном командном процессе, запущенном с cmd.exe /C
в фоновом режиме командной строки:
dir /B /A-D-H "C:\Development\test\TTT*_*" 2>nul
DIR ищет в указанном каталоге
- просто не скрытые файлы из-за
/A-D-H
(атрибут не каталог и не скрытый)
- соответствует шаблону подстановки
TTT*_*
, который также может быть просто *_*
- и вывод для обработки STDOUT в голом формате из-за
/B
только имен файлов с расширением, но без пути к файлу.
Сообщение об ошибке, выводимое DIR для обработки STDERR , если указанный каталог вообще не существует или отсутствует файл, соответствующий шаблону, подавляется путем перенаправления его с помощью 2>nul
к устройству NUL .
Прочтите также статью Microsoft о Использование операторов перенаправления команд для объяснения 2>nul
. Оператор перенаправления >
должен быть экранирован с помощью символа вставки ^
в FOR командной строке, чтобы интерпретироваться как литеральный символ, когда интерпретатор команд Windows обрабатывает эту командную строку перед выполнением команды FOR , которая выполняет встроенную командную строку dir
в отдельном командном процессе, запущенном в фоновом режиме.
FOR захватывает все, записанное в STDOUT запущенного командного процесса, и обрабатывает захваченный вывод построчно.
FOR по умолчанию игнорирует все пустые строки (здесь не встречаются) и все строки, начинающиеся с точки с запятой. Имя файла может начинаться с точки с запятой. По этой причине опция eol=|
используется для переопределения символа конца строки в вертикальной строке, которая не может содержать имя файла, см. Статью Microsoft о Именование файлов, путей и пространств имен . В этом случае при использовании TTT*_*
в качестве шаблона подстановки невозможно, чтобы имя файла начиналось с точки с запятой, но это было бы возможно при использовании *_*
в качестве шаблона подстановки.
FOR будет также разбивать каждую строку на подстроки (токены), используя пробел / табуляцию в качестве разделителей, и назначать только первую строку, разделенную пробелом / табуляцией, указанной переменной цикла A
. Такое поведение разделения здесь нежелательно, поскольку имена файлов могут содержать один или несколько пробелов. Поэтому опция delims=
используется для определения пустого списка разделителей, который полностью запрещает разделение строк и приводит к присвоению полного имени файла с расширением переменной цикла A
.
Внутренний FOR обрабатывает только имя файла (без расширения) как строку. На этот раз имя файла разделяется с использованием подчеркивания в качестве разделителя из-за delims=_
с присвоением только первой строки с подчеркиванием в переменной цикла B
из-за tokens=1
. Ну, tokens=1
является значением по умолчанию при использовании for /F
, поэтому эту строку параметров можно удалить из кода.
Таким образом, внешний FOR присваивает A
, например, TTTxy_test & example!.txt
, а внутренний FOR обрабатывает TTTxy_test & example!
и назначает B
строку TTTxy
.
Команда MD создает в заданном каталоге назначения подкаталог, например, с именем TTTxy
. Сообщение об ошибке выводится также на уже существующий каталог. Это сообщение об ошибке подавляется путем перенаправления его на устройство NUL .
Затем файл перемещается из исходного в возможно только что созданный подкаталог в целевом каталоге с перезаписью существующего файла с тем же именем в целевом каталоге файла.
Внутренний цикл FOR может быть оптимизирован, если нет файлов, начинающихся с подчеркивания или имеющих более одного подчеркивания после первой части имени файла до первого подчеркивания.
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceDir=C:\Development\test"
set "DestDir=C:\Development\test"
for /F "eol=| tokens=1* delims=_" %%A in ('dir /B /A-D-H "%SourceDir%\TTT*_*" 2^>nul') do (
md "%DestDir%\%%A" 2>nul
move /Y "%SourceDir%\%%A_%%B" "%DestDir%\%%A\"
)
endlocal
Параметр tokens=1*
приводит к присвоению первой части имени файла, разделенной подчеркиванием, переменной цикла A
, а остальной части имени файла - следующей переменной цикла B
согласно ASCII-таблице без дальнейшего разделения на подчеркивания.
Но учтите, что оптимизированная версия не работает для имен файлов, таких как
_TTTxy_test & example!.txt
... подчеркивание в начале (игнорируется шаблоном) или TTTxy__test & example!.txt
... более одного подчеркивания после первой части.
Оптимизированная версия может быть дополнительно оптимизирована для одной командной строки:
@for /F "eol=| tokens=1* delims=_" %%A in ('dir /B /A-D-H "C:\Development\test\TTT*_*" 2^>nul') do @md "C:\Development\test\%%A" 2>nul & move /Y "C:\Development\test\%%A_%%B" "C:\Development\test\%%A\"
Ну, а не оптимизированнаяВерсия также может быть записана в виде еще более длинной отдельной командной строки:
@for /F "eol=| delims=" %%A in ('dir /B /A-D-H "C:\Development\test\TTT*_*" 2^>nul') do @for /F "eol=| tokens=1 delims=_" %%B in ("%%~nA") do @md "C:\Development\test\%%B" 2>nul & move /Y "C:\Development\test\%%A" "C:\Development\test\%%B\"
См. также Одна строка с несколькими командами с использованием пакетного файла Windows для объяснения оператора &
.
Для дополнительного удаления TTT
из имени файла при перемещении файла первый пакетный код изменяется с помощью двух дополнительных команд SET и CALL :
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceDir=C:\Development\test"
set "DestDir=C:\Development\test"
for /F "eol=| delims=" %%A in ('dir /B /A-D-H "%SourceDir%\TTT*_*" 2^>nul') do (
for /F "eol=| tokens=1 delims=_" %%B in ("%%~nA") do (
md "%DestDir%\%%B" 2>nul
set "FileName=%%A"
call move /Y "%SourceDir%\%%A" "%DestDir%\%%B\%%FileName:~3%%"
)
)
endlocal
Имя файла присваивается переменной среды FileName
.На значение этой переменной среды нельзя ссылаться просто с помощью %FileName%
, поскольку все ссылки на значения переменных среды с использованием знаков процента заменяются командным процессором Windows во всем блоке команд, начиная с первого (
и заканчивая соответствием )
перед ЗА выполняется вообще.Задержанное расширение обычно используется в таких случаях, но это приведет к тому, что имена файлов, содержащие один или несколько восклицательных знаков, не будут исправлены, обработанные пакетным файлом.
Решение использует %%
по обе стороны отFileName
ссылка на переменную среды вместо %
и принудительный двойной анализ командной строки с помощью команды CALL .
Чтобы понять используемые команды и то, как они работают, откройте командув окне подсказки выполните там следующие команды и внимательно прочитайте все страницы справки, отображаемые для каждой команды.
call /?
dir /?
echo /?
endlocal /?
for /?
md /?
move /?
set /?
setlocal /?