Как создать папку из имени файла и переместить файлы в папку? - PullRequest
0 голосов
/ 14 сентября 2018

Мне нужен пакетный файл Windows, чтобы создать папку на основе части имени файла (часть перед подчеркиванием) и переместить любые файлы, которые начинаются с имени папки, в папку.

I'mне знаком с пакетными файлами Windows.Я гуглил и возился с решением, которое работает, за исключением того, что я не могу вставить имя файла в подчеркивание.

(Да, есть несколько похожих тем, но я ничего не мог использовать, чтобы точно ответить на мой вопрос)

ПОКАЗЫВАЙТЕ мое неудачное решение:

@ECHO OFF
setlocal enabledelayedexpansion
SETLOCAL

SET "sourcedir=C:\Development\test"
PUSHD %sourcedir%
FOR /f "tokens=1*" %%a IN (
 'dir /b /a-d "TTT*_*.*"'
 ) DO (  

 ECHO MD NEED FILE NAME BEFORE UNDERSCORE HERE
 ECHO MOVE "%%a" .\NEED FILE NAME BEFORE UNDERSCORE HERE\
)

(в идеале я бы тоже удалил начальный «TTT» из файлов, но при необходимости мог бы создавать файлы без этого.)

Ответы [ 3 ]

0 голосов
/ 15 сентября 2018

Попробуйте этот код командного файла:

@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 /?
0 голосов
/ 20 сентября 2018

Вы можете рассмотреть возможность использования Tcl / Tk . Tcl / Tk - это язык сценариев с открытым исходным кодом. Вы можете вызвать его как отдельный или выполнить из пакетного файла Windows. Сначала вам нужно будет установить его, если у вас его еще нет. Следующий скрипт Tcl делает то, что вы хотите:

cd "C:/Development/test"
# glob is a tcl command to list all functions that match the requirements
set files [glob TTT*_*]
foreach f $files {
  # use the underscore as a separator to split f and store the parts in dir and fnew
  lassign [split $f "_"] dir fnew
  if {![file exist $dir]} {
    file mkdir $dir
  }
  file rename $f [file join $dir $fnew]
}

На мой взгляд, это очень читаемый скрипт, даже если вы не знаете tcl. Вы можете вызвать этот скрипт из командного файла как:

tclsh script.tcl

если вы сохранили скрипт как script.tcl

0 голосов
/ 14 сентября 2018

Это действительно очень просто:

@echo off
for /f "tokens=1-2 delims=_" %%i in ('dir /b /a-d "TTT*_*"') do (
    if not exist "%%i" mkdir "%%i"
    move "%%i_%%j" "%%i\%%j"
)

Мы делим на _ на 2 токена, %%i все до _ и %%j все после. Мы просто создаем папку (если она не существует), затем перемещаем файл с именем только после _ в новую папку.

Таким образом, в качестве примера файла TTT123_File1.txt создаст папку с именем TTT123 и поместит в нее файл, но переименует его в File1.txt

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