且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何从文件名创建文件夹并将文件移动到文件夹?

更新时间:2022-06-13 08:15:36

尝试此批处理文件代码:

Try this batch file code:

@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在后台的命令行开始:

The first FOR executes in a separate command process started with cmd.exe /C in background the command line:

dir /B /A-D-H "C:\Development\test\TTT*_*" 2>nul

DIR 在指定目录中搜​​索

DIR searches in specified directory for

  • 由于/A-D-H而只是非隐藏文件(属性不是目录,也不是隐藏的)
  • 匹配通配符模式TTT*_*,通配符模式也可能只是*_*
  • 并输出以纯格式处理 STDOUT ,因为/B只是带有文件扩展名的文件名,而没有文件路径.
  • just non-hidden files because of /A-D-H (attribute not directory and not hidden)
  • matching the wildcard pattern TTT*_* which could be also just *_*
  • and outputs to handle STDOUT in bare format because of /B just the file names with file extension, but without file path.

DIR 输出的用于处理 STDERR 的错误消息,如果指定的目录根本不存在或不存在与模式匹配的文件,可以通过使用2>nul到设备 NUL .

The error message output by DIR to handle STDERR if the specified directory does not exist at all or there is no file matching the pattern is suppressed by redirecting it with 2>nul to device NUL.

还要阅读有关

Read also the Microsoft documentation about Using Command Redirection Operators for an explanation of 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 in a separate command process started in background.

FOR 捕获开始命令过程写入 STDOUT 的所有内容,并逐行处理捕获的输出.

FOR captures everything written to STDOUT of started command process and processes the captured output line by line.

FOR 默认情况下会忽略所有空行(此处不出现)和所有以分号开头的行.文件名可以以分号开头.因此,使用选项eol=|将行尾字符重新定义为文件名不能包含的竖线,请参阅Microsoft文档

FOR ignores by default all empty lines (do not occur here) and all lines starting with a semicolon. A file name could begin with a semicolon. For that reason option eol=| is used to redefine end of line character to vertical bar which a file name can't contain, see Microsoft documentation Naming Files, Paths, and Namespaces. In this case on using TTT*_* as wildcard pattern it is not possible that a file name starts with a semicolon, but it would be possible on usage of *_* as wildcard pattern.

FOR 还将使用空格/制表符作为分隔符将每一行拆分为子字符串(令牌),并且仅将第一个由空格/制表符分隔的字符串分配给指定的循环变量A.由于文件名可以包含一个或多个空格字符,因此此处不希望出现这种拆分行为.因此,选项delims=用于定义一个空的定界符列表,该列表将完全禁用行分割,并导致将整个文件名的扩展名分配给循环变量A.

FOR would split up also each line into substrings (tokens) using space/tab as delimiters and would assign just the first space/tab separated string to specified loop variable A. This splitting behavior is not wanted here as file names can contain one or more space characters. Therefore the option delims= is used to define an empty list of delimiters which disables line splitting completely and results in assigning entire file name with extension to loop variable A.

内部的 FOR 仅将文件名(不带扩展名)处理为字符串.这次,由于delims=_,使用下划线作为分隔符来分割文件名,由于tokens=1,仅将第一个下划线分隔的字符串分配给循环变量B.好吧,tokens=1是使用for /F的默认设置,因此可以从代码中删除此选项字符串.

The inner FOR processes just the file name (without extension) as string. This time the file name is split up using the underscore as delimiter because of delims=_ with assigning just first underscore delimited string to loop variable B because of tokens=1. Well, tokens=1 is the default on using for /F and so this option string could be removed from code.

因此,外部 FOR 分配给A,例如TTTxy_test & example!.txt,内部 FOR 处理TTTxy_test & example!并将字符串TTTxy分配给B

So the outer FOR assigns to A for example TTTxy_test & example!.txt and the inner FOR processes TTTxy_test & example! and assigns to B the string TTTxy.

命令 MD 在设置的目标目录中创建一个名称为TTTxy的子目录.在已经存在的目录上也会输出一条错误消息.通过将其重定向到设备 NUL ,可以抑制此错误消息.

The command MD creates in set destination directory a subdirectory for example with name TTTxy. An error message is output also on directory already existing. This error message is suppressed by redirecting it to device NUL.

然后将文件从源移动到目标目录中刚刚创建的子目录,并覆盖文件目标目录中同名的现有文件.

Then the file is moved from source to perhaps just created subdirectory in destination directory with overwriting an existing file with same name in target directory of the file.

当没有文件以下划线开头或从文件名的第一部分到第一个下划线具有多个下划线的文件时,可以优化内部 FOR 循环.

The inner FOR loop could be optimized away when there are never files starting with an underscore or which have more than one underscore after first part of file name up to first underscore.

@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. com/"rel =" nofollow noreferrer> ASCII表,而无需在下划线处进行进一步的划分.

Option tokens=1* results in assigning first underscore delimited part of file name to loop variable A and rest of file name to next loop variable B according to ASCII table without further splitting up on underscores.

但是请考虑到优化版本不适用于文件名

But please take into account that the optimized version does not work for file names like

  • _TTTxy_test & example!.txt ...开头下划线(被模式忽略),或者
  • TTTxy__test & example!.txt ...在第一部分之后有多个下划线.
  • _TTTxy_test & example!.txt ... underscore at beginning (ignored by pattern), or
  • TTTxy__test & example!.txt ... more than one underscore after first part.

优化后的版本可以进一步优化为单个命令行:

The optimized version can be further optimized to a single command line:

@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\"

好吧,未经优化的版本也可以写成更长的单个命令行:

Well, the not optimized version could be also written as even longer single command line:

@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批处理文件的单行多个命令,以获取操作符&的说明.

See also Single line with multiple commands using Windows batch file for an explanation of operator &.

要在移动文件时从文件名中另外删除TTT,请使用两个附加命令 SET CALL 来修改第一个批处理代码:

For additionally removing TTT from file name on moving the file the first batch code is modified with using two additional commands SET and 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命令处理器替换,从第一个(开始并以匹配的)结束 FOR 完全执行.在这种情况下,通常会使用延迟扩展,但这会导致包含一个或多个感叹号的文件名不会被批处理文件纠正.

The file name is assigned to an environment variable FileName. The value of this environment variable cannot be referenced with just using %FileName% because of all references of environment variable values using percent signs are substituted by Windows command processor in entire command block starting with first ( and ending with matching ) before FOR is executed at all. Delayed expansion is usually used in such cases, but that would result here in file names containing one or more exclamation marks would not be corrected processed by the batch file.

解决方案是在FileName环境变量引用的两侧使用%%而不是%,并使用命令 CALL 强制对命令行进行双重分析.

The solution is using %% on both sides of FileName environment variable reference instead of % and force a double parsing of the command line by using command CALL.

要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面.

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.

  • call /?
  • dir /?
  • echo /?
  • endlocal /?
  • for /?
  • md /?
  • move /?
  • set /?
  • setlocal /?
  • call /?
  • dir /?
  • echo /?
  • endlocal /?
  • for /?
  • md /?
  • move /?
  • set /?
  • setlocal /?