当我运行以下批处理时,它会创建一个文件夹“重复”,并显示脚本当前所在文件夹中的重复文件(按大小)。我是 BATCH 的新手,我无法让其将重复文件移动到“重复”文件夹。
@echo off
setlocal EnableDelayedExpansion
if not exist duplicates mkdir duplicates
for /R %%a in (*.*) do (
set "size[%%~Za]=!size[%%~Za]!,%%~Fa"
)
for /F "tokens=2,3* delims=[]=," %%a in ('set size[') do (
if "%%c" neq "" echo %%b,%%c
)
pause
我试过了,if "%%c" neq "" copy %%b duplicates/ rm %%b,copy %%c /duplicates rm %%b
但没用。任何帮助我都感激不尽。谢谢!
请打开命令提示符窗口,运行
help
并查看输出的不完整Windows 命令列表。用于移动文件(或文件夹)的 Windows 命令是move
。可以执行help move
或move /?
查看此命令的帮助输出。还有Windows CMD 命令的 AZ 索引。所提供的代码并不好,原因如下:
!
由于启用了延迟变量扩展,它不适用于完全限定文件名包含一个或多个的文件。=
或,
或[
或的文件,因为在第二个FOR]
循环中使用这些字符作为字符串分隔符。"
环境变量名、等号、以逗号分隔的绝对文件名列表和最后一个组成的,不能超过 8191 个字符。size[
]
"
duplicates
已经存在(例如来自以前的批处理文件执行),则不会忽略此子文件夹中的文件并再次进行处理。具有相同文件大小的文件名的逗号分隔列表很难进一步处理。
目前尚不清楚应该将哪些具有相同文件大小的文件移动到
duplicates
当前工作目录中的子文件夹中,该子文件夹当然可以与包含批处理文件的目录不同。解决方案 1:仅移动相同文件大小的第二个、第三个……文件
批处理文件使用前两个命令行定义所需的执行环境。
接下来在当前工作目录中创建子目录
duplicates
,然后检查该子目录是否存在。如果由于使用的帐户没有权限在当前工作目录中创建子目录而导致子目录不存在,则批处理文件将默默退出,退出代码为 1,表示出现错误。接下来,使用简单的FOR
duplicates
循环确定子目录的完全限定文件夹名称。文件夹名称也可以是批处理文件执行之前已经存在的。Duplicates
DUPLICATES
Windows 上的目录分隔符
\
与/
Linux/Mac 上的不同,如 Microsoft 文档中关于命名文件、路径和命名空间所述。子目录的完全限定文件夹名称中的每个反斜杠
duplicates
接下来都会被替换为两个反斜杠,并且附加两个反斜杠。这对于FINDSTR来说是必要的,即使在字面解释的搜索字符串中,如果前面没有另一个反斜杠,FINDSTR 也会将反斜杠解释为转义字符。如果批处理文件位于当前目录或其子目录中,则也必须忽略它。因此,将确定完全合格的批处理文件名,并将批处理文件名中的每个反斜杠替换为两个反斜杠。
第一个
for /F
循环确保#
当前环境中没有以名称开头的偶然定义的环境变量。后台第二个进程执行了
for /F
另一个命令,启动命令如下:%DuplicatesFolder%
duplicates
已被当前工作目录中子目录的完全限定文件夹名称替换,并以 结尾\
,并且每个反斜杠都用一个反斜杠转义。%BatchFileName%
已被批处理文件的完全限定文件名替换,其中每个反斜杠都用另一个反斜杠转义。该命令行输出在当前目录及其所有子目录中找到的所有文件名及其完整路径,但子目录中的文件名和FINDSTR
duplicates
过滤掉的批处理文件名除外。另请参阅:如何在 Windows 命令提示符中将 OR 运算符与 FINDSTR 命令结合使用?DIR会排除目录以及指向其他文件和文件夹的链接。阅读有关使用命令重定向运算符的 Microsoft 文档,了解
2>nul
和 的解释|
。重定向运算符>
和|
必须^
在FOR命令行上用插入符号进行转义,以便在 Windows 命令解释器在执行命令 FOR 之前处理此命令行时将其解释为文字字符,该命令FOR执行嵌入的dir
命令行以findstr
过滤子目录中的文件duplicates
和当前处理的批处理文件。文件名的输出列表通过处理批处理文件捕获,并在后台启动并完成整个命令行的执行后由FOR
cmd.exe
逐行处理。具有完整路径的文件名可以包含一个或多个空格,默认情况下,这些空格被解释为字符串分隔符。该选项指定一个空的字符串分隔符列表,以便将每个文件名完整地分配给循环变量。cmd.exe
delims=
G
IF条件检查是否已定义名称为 的环境变量,以及当前文件大小。如果存在这样的环境变量,则当前文件与之前处理的另一个文件具有相同的文件大小。根据文件大小,将重复文件移动到当前工作目录的子目录中。如果当前文件是具有该文件大小的第一个文件,则使用字符串值定义名称为 的环境变量和当前文件的文件大小。
#
duplicates
#
1
请注意,即使使用选项,MOVE命令也会显示
/Y
提示,如果文件夹中已经有duplicates
一个与要移动的文件同名且设置了只读属性的文件。在这种情况下,用户必须确认是否应使用要移动的文件替换现有的只读目标文件。要移动的文件的只读属性不会阻止移动文件。由于未找到至少两个具有相同文件大小的文件,因此执行批处理文件后,命令RD会删除空目录。
duplicates
倒数第二行恢复初始执行环境。阅读此答案以了解有关命令SETLOCAL和ENDLOCAL的详细信息。
解决方案 2:移动所有具有相同文件大小的文件
第二个批处理文件是第一个批处理文件的变体。第一个文件的大小与另一个文件相同,也被移动到
duplicates
当前工作目录中的子目录中。当前工作目录及其所有子目录除外,duplicates
最终仅包含根据文件大小确定的唯一文件,可能还包含剩余的空子目录和链接。对于每个文件大小,首先定义一个环境变量,其名称由
#
和带有字符串值的文件大小编号组成1
;然后定义第二个环境变量,其名称也由#
和文件大小编号组成,并以具有#
该文件大小的第一个文件的完全限定文件名结尾。如果发现另一个文件大小相同,则首先检查是否仍定义了具有第一个文件大小相同的文件的文件名的环境变量,如果仍定义,则
duplicates
使用临时启用的延迟变量扩展将文件移动到子目录,并从环境变量列表中删除此环境变量。然后根据文件大小移动重复文件。请注意,由于文件当前正在应用程序中打开,因此可能无法移动。子目录中可能
duplicates
已经包含一个同名文件,由于目标文件当前正在应用程序中打开,因此无法用要移动的文件替换该文件。如果在此批处理文件的典型用例中有必要,可以使用附加命令行更好地处理移动文件时的错误。要了解所使用的命令及其工作原理,请打开命令提示符窗口,在那里执行以下命令,并完整仔细地阅读每个命令显示的帮助页面。
call /?
... 解释%~f0
... 参数 0 的全名是批处理文件名。dir /?
echo /?
endlocal /?
exit /?
findstr /?
for /?
if /?
mkdir /?
或者md /?
move /?
pause /?
rd /?
set /?
setlocal /?
在应用于真实数据之前,请务必先根据测试目录进行验证。
清除以 开头的任何变量名后
size
,此代码扫描源目录,依次将每个完整文件名分配给%%e
。如果 中的驱动器+路径%%e
以文字开头%sourcedir%\duplicates
,则跳过目录,否则sizefilesize|fullfilename|
将建立一个变量。我使用它|
,因为它不是有效的文件名字符(与 不同,
)然后检查已建立的
size*
变量,例如,size37|filename1|
和size37|filename2|
将按顺序列出。%%b
已分配size37
和%%c
文件名。:comparesizes
调用内部例程,size37
与的先前值进行比较lastsize
;设置sameaslast
为y
或不设置任何值(允许使用布尔值进行布尔运算)并存储最后遇到的大小。如果文件具有重复的大小,则
:selectdupdest
调用例程来选择要将文件移动到的重复目录;然后将文件移动move
到选定的重复目录。:selectdupdest
在重复中查找文件名,如果找到,则修改并创建新目录等duplicates1
,duplicates2
直到找到不包含该文件名的目录。结果:所有重复的文件大小都会移动到
duplicates
目录中。所有文件都保留在树中,但duplicates
目录可能包含重复的文件大小。