如何根据文件名开头的数字将PDF文件移动到以相同编号开头的目录中



我尝试移动PDF文件。例如,文件名中有两个空格的文件12345 234456.pdf到文件夹12345-customername中。

我试过这个:

SETLOCAL
SET "sourcedir=E:customer files"
PUSHD "%sourcedir%"
FOR /f "tokens=1*delims= " %a IN ('dir /b /a-d "* *.pdf" ') DO (MOVE "E:customer files%a  %b" "E:customer files%a") 
GOTO :EOF

问题是源目录仅匹配目标文件夹的前 5 个数字,而不是文件夹的全名,并且命令失败。

所以我想知道:

目标是否可以是仅与源文件的前 5 个数字匹配的通配符?

我有一个 PDF 文件12345 345678.pdf.我想将其移动到现有的目录中12345-random customer.源 PDF 文件在移动后可以保持相同的名称。

我认为,您需要这样的批处理文件:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceFolder=E:customer files"
for /F "eol=| delims=" %%I in ('dir /A-D-H /B "%SourceFolder%* *.pdf" 2^>nul') do call :MoveFile "%SourceFolder%%%I"
endlocal
goto :EOF
:MoveFile
for /F "eol=| tokens=1 delims= " %%J in ("%~n1") do set "TargetFolder=%~dp1%%J"
for /D %%J in ("%TargetFolder%*") do move /Y %1 "%%J" & goto :EOF
md "%TargetFolder%"
if errorlevel 1 goto :EOF
move /Y %1 "%TargetFolder%"
goto :EOF

第一个FOR在单独的命令进程中执行,在命令行后台cmd.exe /C启动

dir /A-D-H /B "E:customer files* *.pdf" 2>nul

命令DIR列出到单独命令进程的STDOUT

  • 指定目录中所有非隐藏文件的文件名E:customer files因为/A-D-H
  • 由于/B,只有文件名和文件扩展名的裸格式
  • 匹配通配符模式* *.pdf

DIR会向重定向到设备NUL2>nulSTDERR输出一条错误消息,以在找不到符合这些要求的目录条目时将其禁止显示。

阅读有关使用命令重定向运算符的Microsoft文章,了解2>nul的说明。当 Windows 命令解释器在执行命令 FOR 之前处理此命令行时,重定向运算符>必须使用FOR命令行上的插入字符^进行转义,该命令使用在后台启动的单独命令进程执行嵌入的dir命令行。

FOR捕获输出到单独命令进程的STDOUT的所有内容,并逐行处理捕获的文本。

FOR忽略空行,除非DIR未找到匹配的文件名,否则此处不会出现空行。

默认情况下,FOR忽略使用/F所有以分号开头的行。文件名可以以;开头,因此eol=|用于将行尾字符重新定义为文件名不能包含的竖线。

默认情况下,FOR使用空格/制表符作为分隔符将一行拆分为子字符串(标记),并将第一个空格/制表符分隔的字符串分配给指定的循环变量I。此换行行为由定义分隔符空列表的delims=禁用。

因此,整个文件名被分配给循环变量I该变量与源文件夹路径连接到完全限定文件名并传递给子例程MoveFile

子例程中的第一个FORMoveFile处理没有路径和文件扩展名的文件名字符串,并用%~n1引用,并将其拆分为空格。第一个空格分隔的字符串被分配给指定的循环变量J该变量与引用的源文件的驱动器和路径连接%~dp1始终以反斜杠结尾到环境变量TargetFolder

子例程中的第二个FORMoveFile搜索从当前文件名的第一个空格分隔字符串开始的非隐藏目录,即从 PDF 文件名开头的数字开始。如果在源文件夹中找到与此简单通配符模式匹配的目录,则将其完整限定名分配给循环变量J并执行命令MOVE以将 PDF 文件移动到此文件夹中。然后退出 FOR 循环和子例程MoveFile,批处理文件在文件顶部的第一个FOR命令行上继续执行

否则,源目录中没有当前文件的子目录。因此,批处理文件会创建此目录。如果由于某些原因失败,则退出子例程而不移动当前文件。否则,文件将移动到刚刚创建的目录中。

要了解使用的命令及其工作原理,请打开命令提示符窗口,在那里执行以下命令,并仔细阅读为每个命令显示的所有帮助页面。

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

另请参阅使用 Windows 批处理文件的单行包含多个命令,了解运算符&的说明和 GOTO :EOF 返回到哪里?

您可以使用for /d循环获取文件夹的全名。

(未经测试):

@echo off
SETLOCAL
SET "sourcedir=E:customer files"
PUSHD "%sourcedir%"
FOR /f "tokens=1*delims= " %%a IN ('dir /b /a-d "* *.pdf" ') DO (
for /d  %%c in ("%%a*") do (
MOVE "E:customer files%%a  %%b" "E:customer files%%c"
)
) 
GOTO :EOF

注意:如果您有多个以相同的 5 位数字开头的文件夹,它将尝试将文件移动到每个文件夹(并且仅适用于第一个(在第一个move之后不再可用))

如果您使用的是现代版本的Windows,则可以使用PowerShell。如果对正确移动文件感到满意,请从Move-Itemcmdlet 中删除-WhatIf

=== 移动客户文件.ps1

$sourcedir = 'C:srctcustfilesmovecustomer files'
$destdir = 'C:srctcustfilesmovecustomer'
Get-ChildItem -File -Path $sourcedir -Filter '*.pdf' |
ForEach-Object {
$d = $_.Name -replace '(d+) .*', '$1'
$targetdir = [Io.Path]::Combine($destdir, $d)
if (-not (Test-Path $targetdir)) { mkdir $targetdir | Out-Null }
Move-Item -Path $_.FullName -Destination $targetdir -WhatIf
}

然后,从 cmd.exe 外壳调用它:

powershell -NoProfile -File .Move-CustomerFiles.ps1

最新更新