简体   繁体   English

使用部分名称创建文件夹和移动文件的批处理脚本

[英]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:实施以下方法:

  • split off everything beginning at the first numeric part from the file name;从文件名中拆分从第一个数字部分开始的所有内容;
  • check whether the remainder ends with - which separates a roman number from a decimal one in your sample files;检查余数是否以-结尾,它将示例文件中的罗马数字与十进制数字分开;
  • if it does remove it and remove from the end the longest sequence that consists of characters that may build a roman number without checking if it actually is a valid one;如果它确实删除它并从末尾删除由可能构建罗马数字的字符组成的最长序列而不检查它是否实际上是有效的;

The following very inefficient batch file using only internal commands of the Windows command processor works for files with names matching following conditions:以下仅使用 Windows 命令处理器的内部命令的非常低效的批处理文件适用于名称与以下条件匹配的文件:

  1. A roman number in file name is in range 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.文件名中的罗马数字在IXXXIX (1 到 49)的范围内,罗马数字留给连字符和十进制数字或留给文件扩展名。 The roman number is interpreted case-insensitive by command SET on applying the substitutions.罗马数字在应用替换时由命令SET解释为不区分大小写。
  2. The first decimal digit in range 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.文件名中09范围内的第一个十进制数字被解释为字符,该字符将 substring 用作文件夹名称,其余文件名部分将被忽略为文件夹名称。
  3. Decimal digits at beginning of a file name are ignored for the folder name.文件夹名称忽略文件名开头的十进制数字。
  4. The wildcard pattern passed to the batch file as second argument should end with a file extension.作为第二个参数传递给批处理文件的通配符模式应以文件扩展名结尾。 Something like *.* 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.

相关问题 批量创建基于部分文件名的文件夹并将文件移动到该文件夹​​中 - Batch create folders based on part of file name and move files into that folder 批处理文件根据文件名的一部分将文件移动到文件夹 - Batch File to move files to folders base on part of their name 根据部分文件名批量创建文件夹,然后将它们移动到该文件夹中 - Batch create folders based on part of file name, then move them into that folder 批量创建基于第一部分文件名的文件夹,将文件移至该文件夹 - Batch Create folders based first part filename, move files into that folder 批处理/ Power Shell脚本基于文件名创建文件夹并移动文件 - batch/power shell script to create folders based on file name and move files 根据部分文件名创建文件夹并将文件移动到创建的文件夹中 - Create Folders based on part of file name and move files into the created folder 批处理文件-Windows10。如何将基于文件名中间部分的文件移动到以该部分命名的文件夹中 - Batch file - Windows 10. How to move files based on mid part of their name to folders named after that part 批量执行 Regex 或 powershell 脚本以生成文件夹并在按文件名中的关键字符串排序的相对文件夹中移动文件 - Implement Regex in batch or powershell script to generate folders and move files in relative folders ordered by key string in file name 批量复制/移动文件到同名文件夹 - batch copy/move files to folders with same name 使用批处理文件创建文件夹和移动文件 - Create folders and move files with batch-file
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM