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

时间:2018-10-31 15:37:54

标签: cmd

我尝试移动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文件可以保留相同的名称。

3 个答案:

答案 0 :(得分:0)

您可以使用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位数字开头的文件夹,它将尝试将文件移至每个文件夹(并且仅适用于第一个文件夹(在第一个{{ }}))

答案 1 :(得分:0)

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

@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 将错误消息输出到 STDERR ,并用2>nul重定向到设备 NUL ,以在找不到目录条目时禁止显示该错误消息符合这些要求。

阅读有关Using Command Redirection Operators的Microsoft文章,以获取2>nul的解释。当Windows命令解释器在执行命令之前处理此命令行时,重定向操作符>必须在 FOR 命令行上使用脱字符号^进行转义,才能被解释为文字字符。 FOR ,它将在后台启动的单独命令进程中执行嵌入式dir命令行。

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

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

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

FOR 默认情况下使用空格/制表符将行分隔为子字符串(令牌),并仅将第一个空格/制表符分隔的字符串分配给指定的循环变量Idelims=禁用了行拆分行为,该行定义了一个空的定界符列表。

因此,将整个文件名分配给循环变量I,该变量与源文件夹路径合并为一个完整的限定文件名,并传递给子例程MoveFile

子程序MoveFile中的第一个 FOR 处理文件名 string ,不包含用%~n1引用的路径和文件扩展名,并将其分割成空格。第一个用空格分隔的字符串分配给指定的循环变量J,该变量与以%~dp1引用的源文件的驱动器和路径串联在一起,并始终以反斜杠结尾到环境变量TargetFolder

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

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

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

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

另请参阅Single line with multiple commands using Windows batch file,以了解运算符&Where does GOTO :EOF return to?

答案 2 :(得分:0)

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

=== Move-CustomerFiles.ps1

$sourcedir = 'C:\src\t\custfilesmove\customer files'
$destdir = 'C:\src\t\custfilesmove\customer'

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 shell调用它:

powershell -NoProfile -File .\Move-CustomerFiles.ps1