批处理文件以交叉引用大小并重命名丢失名称的1300个文件

时间:2019-07-09 06:03:42

标签: windows batch-file cmd

我最近(不小心)格式化了一个硬盘,其中包含大约2000个重要的存档文件。我使用了一个数据恢复软件来恢复文件,但没有恢复任何名称(全部标题为“ LostFile_1,LostFile2 ... etc”),而第二个软件恢复了所有名称,但是所有文件都损坏了,不会打开。

我们在代码中间,该代码会交叉引用损坏文件中的专有名称,并根据文件大小将其与丢失的名称文件(LostFile等)进行匹配。

有2个文件夹,一个名为“ RealFiles”的文件夹,具有通用的“ LostFile”名称,但包含工作文件,第二个文件夹“ RealNames”,其名称与真实文件但损坏的文件。我们正在交叉引用匹配的文件大小,并从“ RealNames”文件中提取名称以重命名匹配的未损坏的“ RealFiles”。

我非常感谢Ben Personick在下面的注释中的代码(谢谢!),这几乎可以解决问题,日志显示将其设置为重命名所有文件,但是输出文件仅位于“ Hard_Linked”中重命名并为第一个匹配项创建文件。

用于重命名和交叉引用的代码(Credit Ben Personick):

  @(
    SetLocal EnableDelayedExpansion
    Echo off
    Set "_Src=C:\Path\Lost"
    Set "_Ref=C:\Path\Reference"
    Set "_Lnk=C:\Path\Hard_Linked"
    Set "_Dst=C:\Path\Renamed"
    Set "_Log=C:\Path\Rename.log"
  )

 Set "_J=0"
 For /F "Tokens=*" %%A in ('
   Dir /A-D /B /OSE "%_Src%"
 ') Do (
   Set "_SrcFile!_J!=%%A"
   Set /A "_J+=1"
 )

 Set /A "_J-=1"

 Set "_I=0"
 For /F "Tokens=*" %%A in ('
   Dir /A-D /B /OSE "%_Ref%"
 ') Do (
  Call ECHO.Rename: "%%_SrcFile!_I!%%" - To: "%%A"
  Call ECHO.Rename: "%%_SrcFile!_I!%%" - To: "%%A">>"%_Log%"
  REM Comment the next line to stop maiing hardlinks
  CALL MkLink /H "%_Lnk%\%%A" "%_Src%\%%_SrcFile!_I!%%"
   REM Un-comment the next line to move files to final folder renamed
  REM CALL MOVE /Y "%_Src%\%%_SrcFile!_I!%%" "%_Dst%\%%A"
   Set /A "_I+=1"
  )

 (
   Endlocal
   Exit /b
 )

日志:

Rename: "LostFile_1.file" - To: "Correct Name 1.file"
Rename: "LostFile_2.file" - To: "Correct Name 2.file"
Rename: "LostFile_3.file" - To: "Correct Name 3.file"
Rename: "LostFile_4.file" - To: "Correct Name 4.file"
Rename: "LostFile_5.file" - To: "Correct Name 5.file"

Hard_Linked文件夹中的结果: 正确创建了LostFile1并重命名了正确的名称,但没有重命名为2、3、4、5。

2 个答案:

答案 0 :(得分:1)

好的,这实际上在cmd中很容易。

但是,让我们更进一步,而不是将所有内容都放在一个目录中,将两个目录都放在两个目录中。

此外,我建议在运行日志时先记录一下将重命名的内容,以供检查和/或将文件复制到第三目录以供检查,以确保您获得所需的结果。

因此,由于您不熟悉cmd / batch脚本,因此我想指出,我们有一些关于如何迭代文件的选项,大多数为for, for/FForfiles是遍历文件的常用方法,有时在DIR中使用for /F cmd,或者在WMIC文件列表中使用(尽管值得庆幸的是,WMIC最终因Powershell而被贬低)

如果您只是想根据大小确定每个文件都是正确的,并且大小完全匹配且没有重复,并且可以肯定,那么使用dir cmd可以按大小排序一种实用的方法来快速进行匹配

如果需要在匹配上做更多的事情,那么forforfiles循环将是更好的选择

要在此过程中节省空间而不是复制,我们可以创建硬链接,然后可以测试它们的所有工作,并假设它们可以工作,则可以删除这些硬链接并使用Move命令重命名它们。

  @(
    SetLocal EnableDelayedExpansion
    Echo off
    Set "_Src=C:\Ren\Lost"
    Set "_Ref=C:\Ren\Reference"
    Set "_Lnk=C:\Ren\Hard_Linked"
    Set "_Dst=C:\Ren\Renamed"
    Set "_Log=C:\Ren\Rename.log"
  )

 Set "_J=0"
 For /F "Tokens=*" %%A in ('
   Dir /A-D /B /OSE "%_Src%"
 ') Do (
   Set "_SrcFile!_J!=%%A"
   Set /A "_J+=1"
 )

 Set "_I=0"
 For /F "Tokens=*" %%A in ('
   Dir /A-D /B /OSE "%_Ref%"
 ') Do (
   Call ECHO.Rename: "%%_SrcFile!_I!%%" - To: "%%A"
   Call ECHO.Rename: "%%_SrcFile!_I!%%" - To: "%%A">>"%_Log%"
   REM Comment the next line to stop maiing hardlinks
    CALL MkLink /H "%_Lnk%\%%A" "%_Src%\%%_SrcFile!_I!%%"
   REM Un-comment the next line to move files to final folder renamed
    REM CALL MOVE /Y "%_Src%\%%_SrcFile!_I!%%" "%_Dst%\%%A"
   Set /A "_I+=1"
  )

 (
   Endlocal
   Exit /b
 )

我将在下面稍作解释,但必须喷射atm。

由于工作繁忙,我有机会拿回广告,而我却没有时间花时间解释,我通过添加Set /A "_I+=1"来解决一个错误,这就是为什么它没有前进每次测试文件的值。


这里是示例输出,因为我有时间运行它以确保它能正常工作,并且它完全按我的预期工作。

Y:\>C:\Ren\RenameScript.cmd
Rename: "SomethingOld.ext1" - To: "ReferenceFileCorect_A_Unique1.ext1"
Hardlink created for C:\Ren\Hard_Linked\ReferenceFileCorect_A_Unique1.ext1 <<===>> C:\Ren\Lost\SomethingOld.ext1
Rename: "SomethingOld.txt" - To: "ReferenceFileCorect_A_New_name.txt"
Hardlink created for C:\Ren\Hard_Linked\ReferenceFileCorect_A_New_name.txt <<===>> C:\Ren\Lost\SomethingOld.txt
Rename: "SomethingOld3.txt" - To: "ReferenceFileCorect_A_ThirdName.txt"
Hardlink created for C:\Ren\Hard_Linked\ReferenceFileCorect_A_ThirdName.txt <<===>> C:\Ren\Lost\SomethingOld3.txt

此消息:Hardlink created for C:\Ren\Hard_Linked\ReferenceFileCorect_A_Unique1.ext1 <<===>> C:\Ren\Lost\SomethingOld.ext1是MKLink的输出,如果您未在CMD提示符下看到该消息,则可能未在管理cmd提示符下运行CMD脚本。

我们可以将代码添加到脚本中,以调用PowerShell并在管理cmd提示符下重新启动自身,但是如果直接进行测试,因为它不属于您最初的Q,那么这样做的麻烦就更少了。 / p>

所以我想花点时间解释一下脚本在做什么以及为什么要这么做,以便您自己前进:

 SetLocal EnableDelayedExpansion

我们正在启用“延迟扩展”,以使我们能够通过使用!_var!而不是%_Var%来引用变量来轻松评估for循环内变量的内容,从技术上讲,我们可以不用这个,如果您的任何文件名中都包含!,我们应该禁用它并重新写入一点,如果没有,那就没问题了。

 ECHO OFF

我正在阻止脚本回显正在执行的每一行,因此我们的混乱输出更少了。

设置变量不言自明

这使我们可以轻松地循环变量并在循环内更新其内容,而无需使用CALL。

 Set "_J=0"
 For /F "Tokens=*" %%A in ('
   Dir /A-D /B /OSE "%_Src%"
 ') Do (
   Set "_SrcFile!_J!=%%A"
   Set /A "_J+=1"
 )

在这里,我正在使用DIR快速按大小和扩展名对文件进行排序,并仅返回文件名。 DIR执行此操作的速度非常快,因此,如果您要进行一点排序而不是稍后使用IF比较来匹配文件,则是更可取的。

选项/A-D忽略目录/B仅输出文件名(因为我们不递归)/OSE-/O是选项的“排序依据” SE按大小排序,然后按文件扩展名排序,因此,即使两个文件大小相同,如果扩展名不同,排序顺序也将相同。

所有内容都放在For /F循环中,这是一种解析命令输出的方式,我们使用"Tokens=*"确保将所有非空格返回的广告放置在变量。

DO ()部分中,我们将增加一个临时变量_J,然后通过创建使用_J的值来保存每个文件的值的变量来在内存中创建一个伪数组。从DIR命令返回到循环。 Set "_SrcFile!_J!=%%A"

 Set "_I=0"
 For /F "Tokens=*" %%A in ('
   Dir /A-D /B /OSE "%_Ref%"
 ') Do (
   Call ECHO.Rename: "%%_SrcFile!_I!%%" - To: "%%A"
   Call ECHO.Rename: "%%_SrcFile!_I!%%" - To: "%%A">>"%_Log%"
   REM Comment the next line to stop maiing hardlinks
    CALL MkLink /H "%_Lnk%\%%A" "%_Src%\%%_SrcFile!_I!%%"
   REM Un-comment the next line to move files to final folder renamed
    REM CALL MOVE /Y "%_Src%\%%_SrcFile!_I!%%" "%_Dst%\%%A"
   Set /A "_I+=1"
  )

我们现在再次在参考目录上循环DIR的输出,由于文件集相同,因此顺序将与第一次循环迭代中的过程相同,仅返回的名称将有所不同(即正是我们想要的。)

DO ()内,我们从DIR接收每个结果,将其回显到CLI,使用>>重定向将其回显到日志中,然后创建我们的硬链接,或者使用MOVE重命名文件(如果通过删除“ REM”取消注释该行

(注意,如果我们要回显并记录多行,我会使用CALL到子函数来执行此操作,因此不会有重复的行,但是因为这只是我一次决定保持原样)

由于顺序相同,所以我知道我们正在进行的任何迭代,只要我们确定没有重复,就不必进行任何比较操作(慢)。

我选择在此处创建HARD链接是因为创建它们几乎没有任何开销,并且它们使您可以进行实时测试,以查看文件的外观,然后再将其移动以重命名它们。世界上最好的)

在我自己之前遇到类似的情况,然后(在小时候)手工进行处理。我可以告诉你,我希望我知道20年前的这种技巧,以节省测试文件所需的时间和磁盘。

MKLINK是这类事情的天赐之物。现在,您可以像使用MOVE op一样快了,但是复制的好处是可以确保您不会意外重命名它们并在实际源文件中引起问题。

如果您对结果感到满意,则可以删除所有硬链接,REM退出“硬链接创建”,然后取消注释“ MOVE”行,MOVE行应永久性地对其进行重命名。然后,请务必确保最后删除参考文件,以免意外保存要保存的错误文件。

这是

答案 1 :(得分:1)

  • 通过迭代实际文件名,构建一个大小为[123]作为名称和文件名作为值的(伪)数组。

  • 然后迭代LostFiles并检查是否存在匹配的大小并重命名。

经过测试和增强:

:: Q:\Test\2019\07\09\SO_56946186.cmd
@Echo off & setlocal EnableDelayedExpansion
Set "RealNames=A:\Test\RealNames\*"
Set "RealFiles=A:\Test\RealFiles\LostFile_*"

for %%N in ("%RealNames%") do set "size[%%~zN]=%%~fN"
:: set size
for %%F in ("%RealFiles%") do if defined size[%%~zF] (
    for %%n in ("!size[%%~zF]!") do (
        Ren "%%F" "%%~nn_Fixed%%~xn" && Del "%%~fn"
    )
) else (
    echo no matching size[%%~zF] for %%F
)

仅回显重命名命令,删除回显以执行重命名。

之前列出的目录:

> gci A:\Test\* -Recurse
    Verzeichnis: A:\Test\RealFiles

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2018-11-13     07:52              0 LostFile_1
-a----       2016-11-18     17:12            878 LostFile_2
-a----       2018-01-27     16:17           9811 LostFile_3
-a----       2016-12-10     19:53            435 LostFile_4
-a----       2019-05-27     23:50              2 LostFile_5
-a----       2019-05-27     23:50              7 LostFile_6
-a----       2017-08-18     17:05            985 LostFile_7
-a----       2017-03-21     16:24           1086 LostFile_8
-a----       2017-03-21     16:24           3002 LostFile_9

    Verzeichnis: A:\Test\RealNames

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2018-11-13     07:52              0 1099511627776
-a----       2016-11-18     17:12            878 Choose-CUI.ps1
-a----       2018-01-27     16:17           9811 ConvertTo-Expression.ps1
-a----       2016-12-10     19:53            435 Enum-SpecalFolders.vbs
-a----       2019-05-27     23:50              2 ESC.bin
-a----       2019-05-27     23:50              7 ESC.hex
-a----       2017-08-18     17:05            985 Get-Date.cmd
-a----       2017-03-21     16:24           1086 Get-High20Proc.ps1
-a----       2017-03-21     16:24           3002 High20Proc.html

运行批处理后:

> gci A:\Test\* -Recurse

    Verzeichnis: A:\Test\RealFiles

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2018-11-13     07:52              0 1099511627776_Fixed
-a----       2016-11-18     17:12            878 Choose-CUI_Fixed.ps1
-a----       2018-01-27     16:17           9811 ConvertTo-Expression_Fixed.ps1
-a----       2016-12-10     19:53            435 Enum-SpecalFolders_Fixed.vbs
-a----       2019-05-27     23:50              2 ESC_Fixed.bin
-a----       2019-05-27     23:50              7 ESC_Fixed.hex
-a----       2017-08-18     17:05            985 Get-Date_Fixed.cmd
-a----       2017-03-21     16:24           1086 Get-High20Proc_Fixed.ps1
-a----       2017-03-21     16:24           3002 High20Proc_Fixed.html