简体   繁体   中英

BATCH: How can I copy files to directory based on file name

I've got quite a lot of files I am trying to archive for the company I work for. I am a little familiar with Batch scripts, but I do not quite understand enough to fully get what I am after.

I am trying to copy some files based on the beginning of their file name into folders on our NAS. The files are 7z files and their structure is going to be like so:

  • 5476 BMW Handle-A.7z
  • 5487 Chevy-Imp.7z
  • 5986 Honda Lid-Upper.7z

etc.

The file structure works like this: the four numbers at the beginning is our company job number. On our NAS we have an archive directory with folders in it like this:

  • _5000-5999
  • _6000-6999

And inside of those folders are folders that will contain 250 archive files each. They are formatted like this:

  • _5000-5249
  • _5250-5499
  • _5500-5749
  • _5750-5999

I am looking to create a Batch file that I can drag these 7z files onto and it will read the first four numbers of the file name, and copy it to the proper folder on our NAS.

So for instance the files:

  • 5476 BMW Handle-A.7z
  • 5487 Chevy-Imp.7z

Would copy into

\\nas01\\archive\\ _5000-5999\\ _5250-5499

etc.

The main code I was messing with was this:

@echo off 
for /f "delims=" %%i in ('dir /b /a-d *.7z') do (
set "filename1=%%~i"
setlocal enabledelayedexpansion
set "folder1=!filename1:~0,4!"
mkdir "!folder1!" 2>nul
copy "!filename1!" "!folder1!" >nul
)

What is not working for me is this line:

set "folder1=!filename1:~0,4!"

How can I create some sort of variable to check the file name, create the folders if necessary and copy it to the correct folder? I would appreciate any help on this!

-Dustin

Thanks to some help from commenters, I was able to figure it out. I was having a problem with how to structure the script, but I got it!

@echo off
for /f "delims=" %%i in ('dir /b /a-d *.7z') do (
set "filename=%%~i"
setlocal enabledelayedexpansion
set "folder1=!filename:~0,4!"
set "subfolder1=_!folder1:~0,1!000-!folder1:~0,1!999"
set "firstdigit=!filename:~0,1!"
set "parent=\\nas01\The_Archives"

REM CONDITIONAL STATEMENTS
IF !folder1! GEQ !firstdigit!000 IF !folder1! LEQ !firstdigit!249 SET "subfolder2=_!firstdigit!000-!firstdigit!249"
IF !folder1! GEQ !firstdigit!250 IF !folder1! LEQ !firstdigit!499 SET "subfolder2=_!firstdigit!250-!firstdigit!499"
IF !folder1! GEQ !firstdigit!500 IF !folder1! LEQ !firstdigit!749 SET "subfolder2=_!firstdigit!500-!firstdigit!749"
IF !folder1! GEQ !firstdigit!750 IF !folder1! LEQ !firstdigit!999 SET "subfolder2=_!firstdigit!750-!firstdigit!999"

mkdir "!parent!\!subfolder1!\!subfolder2!" 2>nul
copy "!filename!" "!parent!\!subfolder1!\!subfolder2!" >nul
)

I learned more about Batch today, so it was a day well spent!

Is there a way I can make this to where you just click and drag the files into this Batch script instead of grabbing all of the 7z files in the folder?

Here is a complete batch code for this task using mainly arithmetic expressions and string concatenations to determine the target folder path for each *.7z file in source folder, or alternatively for each file of which name is passed via an argument to the batch file.

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem Source path is the directory of the batch file ending with a backslash.
set "SourcePath=%~dp0"
rem Target path is a UNC path also ending with a backslash.
set "TargetPath=\\nas01\archive\"

rem Run subroutine ProcessFile for each *.7z file in source folder
rem if not at least 1 file was specified on command line to process.
rem Otherwise process the files of which names are passed as arguments
rem to this batch file on starting it. 
if "%~1" == "" (
    for %%I in ("%SourcePath%*.7z") do call :ProcessFile "%%I"
) else (
    for %%I in (%*) do call :ProcessFile "%%~I"
)

rem Restore previous environment and exit this batch file.
endlocal
goto :EOF


rem The subroutine ProcessFile determines the target folders based on
rem first part of the file name separated with one or more spaces from
rem rest of the file name which should be a positive integer number.

rem File names not starting with a valid number are copied (or moved)
rem to the folder _0000-0249\_0000-0249 in specified target folder.

rem For file numbers less than 1000 an extra code is added to copy (or move)
rem those files into folders also having at least 4 digit numbers in name.

:ProcessFile
for /F %%J in ("%~n1") do set "FileNumber=%%J"
set /A FolderNumber1=(FileNumber / 1000) * 1000
set /A FolderNumber2=FolderNumber1 + 999

set /A FolderNumber3=FileNumber - FolderNumber1
if %FolderNumber3% LSS 250 (
    set "FolderNumber3=%FolderNumber1%"
    set /A FolderNumber4=FolderNumber1 + 249
    goto BuildFolderPath
)
if %FolderNumber3% LSS 500 (
    set /A FolderNumber3=FolderNumber1 + 250
    set /A FolderNumber4=FolderNumber1 + 499
    goto BuildFolderPath
)
if %FolderNumber3% LSS 750 (
    set /A FolderNumber3=FolderNumber1 + 500
    set /A FolderNumber4=FolderNumber1 + 749
    goto BuildFolderPath
)
set /A FolderNumber3=FolderNumber1 + 750
set "FolderNumber4=%FolderNumber2%"

:BuildFolderPath
if %FolderNumber1% == 0 (
    set "FolderNumber1=0000"
    set "FolderNumber2=0%FolderNumber2%"
    set "FolderNumber4=0%FolderNumber4%"
    if %FolderNumber3% == 0 (
        set "FolderNumber3=0000"
    ) else (
        set "FolderNumber3=0%FolderNumber3%"
    )
)
set "TargetFolder=%TargetPath%_%FolderNumber1%-%FolderNumber2%\_%FolderNumber3%-%FolderNumber4%"

mkdir "%TargetFolder%" 2>nul
copy /Y "%~1" "%TargetFolder%\" >nul
rem move /Y "%~1" "%TargetFolder%\" >nul
goto :EOF

A subroutine is used instead of doing everything within FOR loop as this makes the task much easier to code because of GOTO can be used in the subroutine. And with a subroutine it is not necessary to use delayed environment variable expansion which is helpful in case of a *.7z file ever contains an exclamation mark.

The main advantage of this solution: it works with numbers in range 0 to 2147482999 in file name.

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 /?
  • copy /?
  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • mkdir /?
  • move /?
  • rem /?
  • setlocal /?

Read also the Microsoft article about Using Command Redirection Operators explaining >nul and 2>nul used to redirect success and error messages to device NUL to suppress them.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM