1

I try to move PDF files. An example is the file 12345 234456.pdf with two spaces in file name into folder 12345-customername.

I have tried this:

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

The problem is that the source directory only matches the first 5 numbers of the destination folder, not the full name of the folder, and the command fails.

So I would like to know:

Can the destination be a wildcard that would match just the first 5 numbers of the source file?

I have a PDF file 12345 345678.pdf. I want to move it into an existing directory 12345-random customer. The source PDF file can stay with the same name once moved.

Jongware
  • 22,200
  • 8
  • 54
  • 100
Derek B
  • 13
  • 2

3 Answers3

0

You can get the full name of the folder with a for /d loop.

(untested):

@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

Note: if you have more than one folder starting with the same 5 digits, it will try to move the file to each of them (and will work only for the first one (not available any more after the first move))

Stephan
  • 53,940
  • 10
  • 58
  • 91
0

I think, you need a batch file like this:

@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

The first FOR executes in a separate command process started with cmd.exe /C in background the command line

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

The command DIR lists to STDOUT of separate command process

  • the file names of all non-hidden files in specified directory E:\customer files because of /A-D-H
  • in bare format with just file name and file extension because of /B
  • matching the wildcard pattern * *.pdf.

DIR outputs an error message to STDERR redirected with 2>nul to device NUL to suppress it if no directory entry is found matching these requirements.

Read the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.

FOR captures everything output to STDOUT of separate command process and process the captured text line by line.

Empty lines are ignored by FOR which do not occur here except no matching file name was found by DIR.

FOR ignores by default on using /F all lines starting with a semicolon. A file name can start with ; and therefore eol=| is used to redefine the end of line character to a vertical bar which a file name cannot contain.

FOR splits up a line by default into substrings (tokens) using space/tab as delimiters and assigns just first space/tab delimited string to specified loop variable I. This line splitting behavior is disabled by delims= which defines an empty list of delimiters.

So the entire file name is assigned to loop variable I which is concatenated with source folder path to a full qualified file name and passed to subroutine MoveFile.

The first FOR in subroutine MoveFile processes the file name string without path and file extension referenced with %~n1 and splits it up on spaces. The first space delimited string is assigned to specified loop variable J which is concatenated with drive and path of source file referenced with %~dp1 ending always with a backslash to an environment variable TargetFolder.

The second FOR in subroutine MoveFile searches for a non-hidden directory starting with the first space separated string of current file name, i.e. starting with the number at beginning of the PDF file names. If a directory matching this simple wildcard pattern is found in the source folder, its full qualified name is assigned to loop variable J and command MOVE is executed to move the PDF file into this folder. Then the FOR loop and the subroutine MoveFile is exited and batch file execution continues on first FOR command line at top of the file.

Otherwise there is no subdirectory in source directory for the current file. So the batch file creates this directory. If that fails for some reasons, the subroutine is exited without moving the current file. Otherwise the file is moved into just created directory.

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

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

See also Single line with multiple commands using Windows batch file for an explanation of operator & and Where does GOTO :EOF return to?

Mofi
  • 46,139
  • 17
  • 80
  • 143
0

If you are on a modern-day version of Windows, PowerShell can be used. When you are satisfied that the files will be moved correctly, remove the -WhatIf from the Move-Item cmdlet.

=== 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
    }

Then, invoke it from a cmd.exe shell with:

powershell -NoProfile -File .\Move-CustomerFiles.ps1
lit
  • 14,456
  • 10
  • 65
  • 119