批量或 Bash 删除数千个文件中的时间戳

Batch or Bash to remove a timestamp in thousands of files

我今天在处理自托管备份系统时犯了一个重大错误,结果删除了大约一半的用户文件夹。幸运的是,备份存在并且能够复制我所有的数据。不好的部分是每个恢复的文件在文件名中都有一个时间戳。

原来是 filename.file 的文件现在是文件名~20170401-1999.file

关于批处理文件或其他什么,我不是太聪明,但是有什么方法可以将 BAT 编程为 运行 通过每个文件名并取出时间戳?每个时间戳都以 ~ 开头,以文件类型的句点结束。因此,删除波浪号和波浪号之后的所有内容并停在句点之前的字符处即可解决问题。

大约有 4600 个文件需要用各种文件类型扩展名进行修复。我在 Windows 10 Pro 上并且能够使用 powershell 或 bash 来修复错误。我安装了 Windows Linux 子系统,因此 bash 脚本也是可以接受的。

只是我的一些想法。

您可以遍历文件,对于每个文件名,您可以将匹配正则表达式 /~\d+-\d+/ 的 sub-string 替换为 ""(即空字符串)并使用修改后的字符串作为文件的新名称。

PowerShell 提供了一个简单的解决方案:

Get-ChildItem -Recurse -File -Filter *~* | 
  Rename-Item -NewName { $_.Name -replace '~[^.]+' } -WhatIf
  • -WhatIf 预览重命名操作;删除它,一旦您确认该命令将按预期工作。

  • 为简单起见,我假设任何包含 ~ 的文件名都必须重命名;如果必须消除误报,可以细化匹配:
    Get-ChildItem -Recurse -File *~[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9].*

  • 匹配仅限于 文件 (-File),位于当前目录的 子树 中的任何位置(-Recurse).
    要仅匹配当前目录中 直接 的文件,请删除 -Recurse

  • 传递给 Rename-Item cmdlet 的 -NewName 参数的脚本块 ({ ... }) 计算新文件名:

    • $_.Name returns 输入文件的名称($_ 是 PowerShell 的自动变量,用于表示手头的输入对象)。
    • -replace '~[^.]+' 执行 regex-based 字符串替换:'~[^.]+' 匹配 ~ 后跟 [= 以外的任何非空字符序列 (+) 26=] ([^.]).;不指定替换字符串会隐式使用空字符串,以便有效地从名称中删除匹配部分。
@ECHO OFF
SETLOCAL

SET "sourcedir=U:\sourcedir"
FOR /f "delims=" %%a IN (
 'dir /b /s /a-d "%sourcedir%\*" '
 ) DO (
 FOR /f "tokens=1,2delims=~" %%p IN ("%%~na") DO (
  IF "%%q" neq "" ECHO(REN "%%a" "%%~p%%~xa"
 )
)

GOTO :EOF

您需要更改 sourcedir 的设置以适合您的情况。

所需的 REN 命令仅 ECHOed 用于测试目的。 确认命令正确后,将ECHO(REN更改为REN以实际重命名文件。

使用基本形式的子目录执行目录扫描,不带目录名称并分配给 %%a。然后使用 ~ 作为分隔符将在 %%p%%q 中找到的全名的名称部分标记化。如果第二个标记不为空,那么我们在 %%q 中有一个时间戳,因此从 %%p 中的部分和 %%a

中的扩展名形成新文件名

没有正则表达式的 mklement0 变体

 Get-ChildItem -Recurse -File -Filter *~*.file | 
     rename-item -NewName {"{0}{1}" -f ($_.BaseName -split "~")[0], $_.Extension  } -WhatIf

一个简短的版本:

 gci -Rec -File -Filter *~*.file | ren -n {"{0}{1}" -f ($_.Base -split "~")[0], $_.Extension  } -WhatIf