How to move files from a source directory to a destination directory with name of first part of file name?

风流意气都作罢 提交于 2020-07-07 12:26:20

问题


I have written the batch file below with the help of others, but I don't have much experience and so this is a bit difficult for me.

I'm trying to transfer PDF files from a specific location to individual folders in another location. Each file name is in this format RANSOM-NH_2018-08-07_5485A635.pdf and based on RANSOM-NH_ the batch file should transfer/move the PDF file to it's proper folder named as such RANSOM-NH_Ransom INC. So based on the initial part of the file name, the file should be moved to folder of which name begins with first part of file name.

Some examples of file and folder names:

File names:

RANSOM-NH_2018-06-20_2018_5849.pdf
GREENWOOD_2018-07-02_66902.pdf
GLSCIENCES_2018-07-24_24811.pdf
CPI_2018-08-01_20039035.pdf
ALDR_2018-08-08_545477636.pdf
ACCQTRAX_2018-07-26_173845.pdf

Folder names:

RANSOM-NH_Ransom INC
GREENWOOD_Greenwood Products, Inc
GLSCIENCES_GL Sciences, Inc
CPI_CPI International
ALDR_Sigma-Aldrich, Inc
ACCQTRAX_AccQtrax

The problem I have is that the script written still moves the file RANSOM-NH8_ in the same folder which it shouldn't do at all.

@ECHO OFF
SETLOCAL
SET "sourcedir=C:\Users\Alpha\Documents\NOTEPAD Coding\File Transfer Coding\Files"
SET "destdir=C:\Users\Alpha\Documents\NOTEPAD Coding\File Transfer Coding\Transfer"
FOR /f "delims=" %%a IN ('dir /b /a-d "%sourcedir%\*.pdf" ') DO (
    FOR /f "tokens=1 delims=_-" %%b IN ("%%a") DO (
        FOR /f "delims=" %%d IN ('dir /b /ad "%destdir%\*%%b*" ') DO (
            MOVE "%sourcedir%\%%a" "%destdir%\%%d\"
        )
    )
)
GOTO :EOF

回答1:


Try this batch file code:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceDir=%UserProfile%\Documents\NOTEPAD Coding\File Transfer Coding\Files"
set "DestDir=%UserProfile%\Documents\NOTEPAD Coding\File Transfer Coding\Transfer"

for /F "eol=| delims=" %%A in ('dir /B /A-D-H "%SourceDir%\*_????-??-??_*.pdf" 2^>nul') do (
    for /F "eol=| tokens=1 delims=_" %%B in ("%%~nA") do (
        for /D %%C in ("%DestDir%\%%B_*") do move /Y "%SourceDir%\%%A" "%%C\"
    )
)

endlocal

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

dir /B /A-D-H "C:\Users\Alpha\Documents\NOTEPAD Coding\File Transfer Coding\Files\*_????-??-??_*.pdf" 2>nul

DIR searches in specified directory for

  • just non-hidden files because of /A-D-H (attribute not directory and not hidden)
  • matching the wildcard pattern *_????-??-??_*.pdf which could be also just *_*.pdf
  • and outputs to handle STDOUT in bare format because of /B just the file names with file extension, but without file path.

The error message output by DIR to handle STDERR if the specified directory does not exist at all or there is no file matching the pattern is suppressed by redirecting it with 2>nul to device NUL.

Read the Microsoft documentation 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 in a separate command process started in background.

FOR captures everything written to STDOUT of started command process and processes the captured output line by line.

FOR ignores by default all empty lines (do not occur here) and all lines starting with a semicolon. A file name could begin with a semicolon. For that reason option eol=| is used to redefine end of line character to vertical bar which a file name can't contain, see Microsoft documentation page Naming Files, Paths, and Namespaces.

FOR would split up also each line into substrings (tokens) using space/tab as delimiters and would assign just the first space/tab separated string to specified loop variable A. This splitting behavior is not wanted here as file names can contain one or more space characters. Therefore the option delims= is used to define an empty list of delimiters which disables line splitting completely and results in assigning entire file name with extension to loop variable A.

The second FOR processes just the file name (without extension) as string. This time the file name is split up using the underscore as delimiter because of delims=_ with assigning just first underscore delimited string to loop variable B because of tokens=1. Well, tokens=1 is the default on using for /F and so this option string could be removed from code.

So the first FOR assigns to A for example RANSOM-NH_2018-08-07_5485A635.pdf and the second FOR processes RANSOM-NH_2018-08-07_5485A635 and assigns to B the string RANSOM-NH.

The third FOR with option /D searches for non-hidden directories in destination directory starting with string assigned to loop variable B and an underscore. If such a directory is found, its name with full path is assigned to loop variable C and executes the command MOVE.

The file is moved from source to existing subdirectory in destination directory with overwriting an existing file with same name in target directory of the file.

The second FOR loop could be optimized away when there are never PDF files starting with an underscore or which have more than one underscore before the date part.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceDir=%UserProfile%\Documents\NOTEPAD Coding\File Transfer Coding\Files"
set "DestDir=%UserProfile%\Documents\NOTEPAD Coding\File Transfer Coding\Transfer"

for /F "eol=| tokens=1* delims=_" %%A in ('dir /B /A-D-H "%SourceDir%\*_????-??-??_*.pdf" 2^>nul') do (
    for /D %%C in ("%DestDir%\%%A_*") do move /Y "%SourceDir%\%%A_%%B" "%%C\"
)

endlocal

Option tokens=1* results in assigning first underscore delimited part of file name to loop variable A and rest of file name to next loop variable B according to ASCII table without further splitting up on underscores.

But please take into account that the optimized version does not work for file names like

  • _RANSOM-X_2018-08-07_5485A635.pdf ... underscore at beginning, or
  • RANSOM-Y__2018-08-07_5485A635.pdf ... more than one underscore left to date part.

The optimized version can be further optimized to a single command line:

@for /F "eol=| tokens=1* delims=_" %%A in ('dir /B /A-D-H "%UserProfile%\Documents\NOTEPAD Coding\File Transfer Coding\Files\*_????-??-??_*.pdf" 2^>nul') do @for /D %%C in ("%UserProfile%\Documents\NOTEPAD Coding\File Transfer Coding\Transfer\%%A_*") do @move /Y "%UserProfile%\Documents\NOTEPAD Coding\File Transfer Coding\Files\%%A_%%B" "%%C\"

Well, the not optimized version could be also written as even longer single command line:

@for /F "eol=| delims=" %%A in ('dir /B /A-D-H "%UserProfile%\Documents\NOTEPAD Coding\File Transfer Coding\Files\*_????-??-??_*.pdf" 2^>nul') do @for /F "eol=| tokens=1 delims=_" %%B in ("%%~nA") do @for /D %%C in ("%UserProfile%\Documents\NOTEPAD Coding\File Transfer Coding\Transfer\%%B_*") do @move /Y "%UserProfile%\Documents\NOTEPAD Coding\File Transfer Coding\Files\%%A" "%%C\"

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.

  • dir /?
  • echo /?
  • endlocal /?
  • for /?
  • move /?
  • set /?
  • setlocal /?


来源:https://stackoverflow.com/questions/52286297/how-to-move-files-from-a-source-directory-to-a-destination-directory-with-name-o

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!