[英]Batch script to create folders and move files using part of their name
I have a file list as:我有一个文件列表:
Pcat2.zip
Pcat3.zip
Pcat22.zip
PcatGig10.zip
PcatGig21.zip
Pcolt2ned.zip
PColt3ned.zip
PColt10ned.zip
PColtI-1.zip
PColtIII-6.zip
PcoltIII-11.zip
PcoltIII-18.zip
PcoltIV-2.zip
PetPap25.zip
Pier4.zip
Pier16.zip
ProvSegrIV-4.zip
ProvSegrIII-1.zip
AttFIII-29.zip
AttFlI-5.zip
AttFlII-20.zip
AttFlVI-18.zip
I tried to use a script which created directories according to a key string in file name, and move the files into them, like this:我尝试使用根据文件名中的键字符串创建目录的脚本,并将文件移动到其中,如下所示:
|
+---Pcat
| Pcat2.zip
| Pcat3.zip
| Pcat22.zip
|
+---PcatGig
| PcatGig10.zip
| PcatGig21.zip
|
+---Pcolt
| Pcolt2ned.zip
| PColt3ned.zip
| PColt10ned.zip
| PColtI-1.zip
| PColtIII-6.zip
| PcoltIII-11.zip
| PcoltIII-18.zip
| PcoltIV-2.zip
|
+---PetPap
| PetPap25.zip
|
+---Pier
| Pier4.zip
| Pier16.zip
|
+---ProvSegr
| ProvSegrIV-4.zip
| ProvSegrIII-1.zip
|
+---AttF
| AttFIII-29.zip
|
\---AttFl
AttFlI-5.zip
AttFlII-20.zip
AttFlVI-18.zip
However, I also want to strip decimal and Roman-like numbers但是,我也想去掉十进制和类似罗马的数字
I-5
III-6
VI-18
VI-18
III-29
...
To accomplish that I tried this script, but it doesn't work.为了实现这一点,我尝试了这个脚本,但它不起作用。 I take a look here Implement Regex in batch or powershell script to generate folders and move files in relative folders ordered by key string in file name我在这里看一下批量执行正则表达式或 powershell 脚本以生成文件夹并在文件名中按字符串排序的相关文件夹中移动文件
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "SPLITCHAR=-" & rem // (a single character to split the file names)
set "SEARCHSTR=_" & rem // (a certain string to be replaced by another)
set "REPLACSTR= " & rem // (a string to replace all found search strings)
set "OVERWRITE=" & rem // (set to non-empty value to force overwriting)
rem // Get file location and pattern from command line arguments:
set "LOCATION=%~1" & rem // (directory to move the processed files into)
set "PATTERNS=%~2" & rem // (file pattern; match all files if empty)
rem /* Prepare overwrite flag (if defined, set to character forbidden
rem in file names; this affects later check for file existence): */
if defined OVERWRITE set "OVERWRITE=|"
rem // Continue only if target location is given:
if defined LOCATION (
rem // Create target location (surpress error if it already exists):
2> nul md "%LOCATION%"
rem /* Loop through all files matching the given pattern
rem in the current working directory: */
for /F "eol=| delims=" %%F in ('dir /B "%PATTERNS%"') do (
rem // Process each file in a sub-routine:
call :PROCESS "%%F" "%LOCATION%" "%SPLITCHAR%" "%SEARCHSTR%" "%REPLACSTR%"
)
)
endlocal
exit /B
:PROCESS
rem // Retrieve first argument of sub-routine:
set "FILE=%~1"
rem // Split name at (first) split character and get portion in front:
for /F "delims=%~3" %%E in ("%~1") do (
rem // Append a split character to partial name:
set "FOLDER=%%E%~3"
)
setlocal EnableDelayedExpansion
rem // Right-trim partial name:
if not "%~4"=="" set "FOLDER=!FOLDER:%~4%~3=!"
set "FOLDER=!FOLDER:%~3=!"
rem /* Check whether partial name is not empty
rem (could happen if name began with split character): */
if defined FOLDER (
rem // Replace every search string with another:
if not "%~4"=="" set "FOLDER=!FOLDER:%~4=%~5!"
rem // Create sub-directory (surpress error if it already exists):
2> nul md "%~2\!FOLDER!"
rem /* Check if target file already exists; if overwrite flag is
rem set (to an invalid character), the target cannot exist: */
if not exist "%~2\!FOLDER!\!FILE!%OVERWRITE%" (
rem // Move file finally (surpress `1 file(s) moved.` message):
1> nul move /Y "!FILE!" "%~2\!FOLDER!"
)
)
endlocal
exit /B
The script requires the directory containing all the files to process as the first command line argument.该脚本需要包含所有要处理的文件的目录作为第一个命令行参数。 The created sub-directories are placed therein.创建的子目录放置在其中。 An optional second command line argument defines a file name pattern to filter certain file types/names.可选的第二个命令行参数定义文件名模式以过滤某些文件类型/名称。 Supposing it is saved as D:\Script\build-folder-hierarchy.bat, the files are contained in D:\Data, and you want to handle *.zip files only, run it as follows:假设保存为 D:\Script\build-folder-hierarchy.bat,文件包含在 D:\Data 中,您只想处理 *.zip 文件,运行如下:
"C:\Script\build-folder-hierarchy.bat" "C:\Data" "*.zip"
Here is a script that accomplishes the task you require (see all the explanatory rem
remarks):这是一个完成您需要的任务的脚本(请参阅所有解释性rem
备注):
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ROOT=%~dp0TEST" & rem // (target directory containing files to process)
set "_MASK=*.zip" & rem // (pattern to match the files against)
set "_SEP=-" & rem // (separator between roman and decimal numbers)
set "_ROMAN=I V X L C D M" & rem // (characters that build up roman numbers)
rem // Change into the target directory:
pushd "%_ROOT%" && (
rem // Loop through all matching files:
for /F "delims= eol=|" %%F in ('dir /B /A:-D-H-S "%_MASK%"') do (
rem // Store full file name and base name in variables:
set "FILE=%%F" & set "NAME=%%~nF"
rem // Toggle delayed expansion to avoid trouble with `!`:
setlocal EnableDelayedExpansion
rem /* Split off (first) group of decimal numerals and everything after from
rem base name: */
for /F "delims=0123456789 eol=0" %%E in ("_!NAME!") do (
endlocal
rem // Store resulting file name prefix in variable:
set "PREF=%%E"
setlocal EnableDelayedExpansion
rem /* Check whether last character is the predefined separator character
rem between roman and decimal numbers and remove it in case; afterwards,
rem split off all characters that may build up a roman number: */
set "PREF=!PREF:*_=!"
if defined PREF if "!PREF:~-1!"=="!_SEP!" (
set "PREF=!PREF:~,-1!"
call :ROMAN PREF PREF
)
)
rem // Create sub-directory named like the retrieved file name prefix:
2> nul md "!PREF!"
rem // Move the currently iterated file into the sub-directory (no overwrite):
if not exist "!PREF!\!FILE!" > nul move /Y "!FILE!" "!PREF!"
endlocal
)
rem // Return from the target directory:
popd
)
endlocal
exit /B
:ROMAN
rem // Remove roman number from the end of a provided string:
set "#STR=%~2"
set "#RTN=%~1"
set "%#RTN%=!%#STR%!"
:ROMAN_LOOP
if defined %#RTN% (
rem /* Check whether the last character of the string is a valid roman numeral
rem and split it off in case: */
set "FLAG=" & for %%R in (!_ROMAN! !_ROMAN! !_ROMAN!) do (
if "!%#RTN%:~-1!"=="%%R" set "FLAG=#"
)
if defined FLAG set "%#RTN%=!%#RTN%:~,-1!" & goto :ROMAN_LOOP
)
exit /B
The following approach is implemented:实施以下方法:
-
which separates a roman number from a decimal one in your sample files;检查余数是否以-
结尾,它将示例文件中的罗马数字与十进制数字分开;The following very inefficient batch file using only internal commands of the Windows command processor works for files with names matching following conditions:以下仅使用 Windows 命令处理器的内部命令的非常低效的批处理文件适用于名称与以下条件匹配的文件:
I
to XXXIX
(1 to 49) and the roman number is left to a hyphen and a decimal digit or left to the file extension.文件名中的罗马数字在I
到XXXIX
(1 到 49)的范围内,罗马数字留给连字符和十进制数字或留给文件扩展名。 The roman number is interpreted case-insensitive by command SET on applying the substitutions.罗马数字在应用替换时由命令SET解释为不区分大小写。0
to 9
in the file name is interpreted as character which delimits the substring to use as folder name from the remaining file name part which is ignored for the folder name.文件名中0
到9
范围内的第一个十进制数字被解释为字符,该字符将 substring 用作文件夹名称,其余文件名部分将被忽略为文件夹名称。*.*
results in processing only the files with a file extension as the first file has which is returned by the file system to the command process processing the batch file and not all files in source folder.像*.*
这样的东西会导致仅处理具有文件扩展名的文件,因为文件系统将文件系统返回给处理批处理文件的命令进程,而不是源文件夹中的所有文件。The batch file code is:批处理文件代码为:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceFolder=%~1"
if not defined SourceFolder set "SourceFolder=%CD%"
for %%I in ("%SourceFolder%") do set "SourceFolder=%%~fI"
if not "%SourceFolder:~-1%" == "\" set "SourceFolder=%SourceFolder%\"
set "FilePattern=%~2"
if not defined FilePattern set "FilePattern=*.zip"
for /F "tokens=* delims=?* eol=|" %%I in ("%FilePattern%") do if "%FilePattern%" == "%%I" if "%FilePattern:~0,1%" == "." (set "FilePattern=*%FilePattern%") else set "FilePattern=*.%FilePattern%"
for %%I in ("%SourceFolder%%FilePattern%") do set "FileExtension=%%~xI" & goto ProcessFiles
setlocal EnableDelayedExpansion
echo ERROR: There are no files matching the pattern !FilePattern! in folder:
echo "!SourceFolder!"
endlocal
echo/
pause
goto :EOF
:ProcessFiles
pushd "%SourceFolder%" || goto :EOF
for /F "eol=| delims=" %%I in ('dir "%FilePattern%" /A-D /B /O-N 2^>nul') do (
set "FileName=%%I"
set "FolderName=%%I"
setlocal EnableDelayedExpansion
for %%J in (XXXIX XXXVIII XXXVII XXXVI XXXV XXXIV XXXIII XXXII XXXI XXX) do (
for %%K in (0 1 2 3 4 5 6 7 8 9) do set "FolderName=!FolderName:%%J-%%K=0!"
set "FolderName=!FolderName:%%J%FileExtension%=0%FileExtension%!"
)
for %%J in (XXIX XXVIII XXVII XXVI XXV XXIV XXIII XXII XXI XX) do (
for %%K in (0 1 2 3 4 5 6 7 8 9) do set "FolderName=!FolderName:%%J-%%K=0!"
set "FolderName=!FolderName:%%J%FileExtension%=0%FileExtension%!"
)
for %%J in (XIX XVIII XVII XVI XV XIV XIII XII XI X) do (
for %%K in (0 1 2 3 4 5 6 7 8 9) do set "FolderName=!FolderName:%%J-%%K=0!"
set "FolderName=!FolderName:%%J%FileExtension%=0%FileExtension%!"
)
for %%J in (IX VIII VII VI V IV III II I) do (
for %%K in (0 1 2 3 4 5 6 7 8 9) do set "FolderName=!FolderName:%%J-%%K=0!"
set "FolderName=!FolderName:%%J%FileExtension%=0%FileExtension%!"
)
for /F "eol=| delims=0123456789" %%J in ("!FolderName!") do (
endlocal
set "FolderName=%%J"
setlocal EnableDelayedExpansion
)
if "!FileName!" == "!FolderName!" (
endlocal
set "FolderName=%%~nI"
if not defined FolderName set "FolderName=%%~xI"
setlocal EnableDelayedExpansion
)
md "!FolderName!" 2>nul
move /Y "!FileName!" "!FolderName!\" >nul
endlocal
)
popd
endlocal
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.要了解使用的命令及其工作原理,请打开命令提示符window,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。
call /?
... explains how to reference batch file arguments as done with %~1
and %~2
. ...解释了如何引用批处理文件 arguments 与%~1
和%~2
一样。dir /?
echo /?
endlocal /?
for /?
goto /?
if /?
md /?
move /?
pause /?
popd /?
pushd /?
set /?
setlocal /?
Read the Microsoft documentation about Using command redirection operators for an explanation of 2>nul
.阅读有关使用命令重定向运算符的 Microsoft 文档,了解2>nul
的说明。 The redirection operator >
must be escaped with caret character ^
on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir
command line with using a separate command process started in background.当 Windows 命令解释器在执行命令FOR执行嵌入式dir
命令行并使用在后台启动的单独命令进程之前处理此命令行时,重定向运算符>
必须在FOR命令行上使用脱字符^
进行转义,以将其解释为文字字符。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.