1

I have file in below format in my Windows server folder:

C:\ABC\abcdef - ggggg hhhhhh iiii jj xxxx kkk - pp qq Sep 21, 2021.txt

I need to check if the file exists in the folder and get the date from the file name. Then the file should be moved to another folder with a new file name with source file date append in MMddyyyy format.

The file should be moved to directory:

C:\ABC\DEF

with the name:

abcdef_xxxx_09212021.txt

I need help to write the Windows batch script to get the date from source file name and move the file with using that date reformatted in new file name.

I figure out file move and rename, but need help to hold date value and then change the format from MMM dd, yyyy to MMddyyyy and append with new file name as in below command line:

IF EXIST "C:\ABC\abcdef - ggggg hhhhhh iiii jj xxxx kkk -*.txt" move /Y "C:\ABC\abcdef - ggggg hhhhhh iiii jj xxxx kkk -*.txt" C:\ABC\DEF\abcdef_xxxx_.txt
aschipfl
  • 33,626
  • 12
  • 54
  • 99
YaS
  • 11
  • 2

2 Answers2

0

The file moving task with renaming the file with date in file name reformatted can be done with following batch file:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "BaseFolder=C:\ABC"
set "!Jan=01"
set "!Feb=02"
set "!Mar=03"
set "!Apr=04"
set "!May=05"
set "!Jun=06"
set "!Jul=07"
set "!Aug=08"
set "!Sep=09"
set "!Oct=10"
set "!Nov=11"
set "!Dec=12"
for /F "eol=| delims=" %%G in ('dir "%BaseFolder%\* - * * * * * * - * * * *, *.txt" /A-D-H /B 2^>nul') do for /F "eol=| tokens=1,7,12-14 delims=, " %%H in ("%%G") do for /F "tokens=2 delims==" %%# in ('set !%%J 2^>nul') do md "%BaseFolder%\DEF" 2>nul & move /Y "%BaseFolder%\%%G" "%BaseFolder%\DEF\%%H_%%I_%%#%%K%%L" >nul
endlocal

The first two command lines define completely the required execution environment.

There is next defined the path to base folder with the text files to move into a subfolder of the base folder assigned to environment variable BaseFolder.

The next command lines define environment variables with abbreviated month as name preceded with ! and their corresponding two digit numbers as values.

The first FOR loop starts in background one more cmd.exe with option /c and the command line specified within ' appended as additional arguments to search in base folder with a wildcard pattern for the text files to move. The output of DIR to handle STDOUT (standard output) of the cmd.exe process started in background is captured by cmd.exe processing the batch file. The captured lines are the file names of all non-hidden *.txt files matched by the wildcard pattern.

The first FOR loop processes one line after the other after started cmd.exe terminated itself. There is by default first split up each line into substrings using normal space and horizontal tab as string delimiters. If the first substring starts with a semicolon, the line is ignored for further processing. Otherwise the first substring is assigned to the specified loop variable and FOR executes the commands specified next. This behavior is not wanted here as the file names definitely contain spaces and it is perhaps even possible that a file name starts with a semicolon. For that reason the option eol=| is used to define the vertical bar as end of line character which no file name can contain ever and option delims= is used to specify an empty list of string delimiters to disable the line splitting behavior. So the entire file name as output by DIR without path is assigned to the loop variable G.

The second FOR processes the file name string with file extension. This time the splitting behavior is wanted using comma and normal space as string delimiters as there are of interest the following substrings:

  1. The first substring abcdef referenced with tokens=1 assigned to the specified loop variable H.
  2. The seventh substring xxxx referenced with 7 in the tokens= option string assigned to next loop variable I according to the ASCII table.
  3. The twelfth substring Sep referenced with 12 in the tokens= option string assigned to next but one loop variable J.
  4. The thirteenth substring 21 referenced with - between 12 and 14 in the tokens= option string assigned to loop variable K.
  5. The fourteenth substring 2021.txt referenced with 14 in the tokens= option string assigned to loop variable L.

The file names contain perhaps one or more ! and for that reason it is better to avoid the usage of referencing environment variables which would require the usage of delayed expansion. There are also not many files to process per weekday.

For that reason the two digit number of the abbreviated month in file name is get by using one more FOR command to run in background cmd.exe with option /c and the command SET with the abbreviated month as environment variable name with a preceding !. The command SET outputs to handle STDOUT of the background command process all environment variables starting with an exclamation mark and the abbreviated month. The exclamation mark is just for avoiding getting output by chance another environment variable of which name starts also with the three characters of the current month abbreviation. Environment variable names usually do not start with an exclamation mark, at least not any predefined Windows environment variable.

SET outputs the variable name, an equal sign and the assigned value. This output is captured and processed by the third FOR using this time the equal sign as delimiter and getting assigned to specified loop variable # just the two digit number after the equal sign.

So there are now all substrings assigned to loop variables needed in new file name.

Therefore the command MD is executed to create the destination directory if not yet existing with suppressing the error message on already existing by redirecting the error message from handle STDERR (standard error) to device NUL.

Next is executed independent on result of command MD the command MOVE to move the file in base folder with file name and extension assigned to loop variable G of first FOR to the destination folder with the new file name being concatenated with the substrings determined by second and third FOR. The message output of the successful movement of one file is suppressed by redirecting it to the device NUL while an error message would be output into the console window.

The last command ENDLOCAL restores the initial environment.

The following batch file could be also used if drive C: is using NTFS as file system and the text files contain never an exclamation mark in their file names nor in base folder path.

@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "BaseFolder=C:\ABC"
set "Jan=01"
set "Feb=02"
set "Mar=03"
set "Apr=04"
set "May=05"
set "Jun=06"
set "Jul=07"
set "Aug=08"
set "Sep=09"
set "Oct=10"
set "Nov=11"
set "Dec=12"
md "%BaseFolder%\DEF" 2>nul 
for %%G in ("%BaseFolder%\* - * * * * * * - * * * *, *.txt") do for /F "eol=| tokens=1,7,12-14 delims=, " %%H in ("%%~nxG") do move /Y "%%G" "%BaseFolder%\DEF\%%H_%%I_!%%J!%%K%%L" >nul
endlocal

This batch file is executed faster as there are no other cmd.exe instances started in background and the destination folder is created only once (hopefully successful). It uses delayed expansion to get the two digit number of the abbreviated month in file name and for that reason only two FOR loops are necessary:

  1. The first FOR loop is for accessing the file system on each iteration of this FOR loop to get next file name matching the wildcard pattern with full path directly from the file system. That works with moving files on NTFS drives, but can fail to work correct on FAT32 or exFAT drives as on FAT drives the file system entries changes with each successful movement of a file. For that reason it is in general better to get first loaded into the memory of cmd.exe processing the batch file the list of all files of which name matches the wildcard pattern as done by the first batch file and then process this list in memory instead of the file system entries permanently changing on each loop iteration.
  2. The second FOR loop is for getting the substrings from the file name needed in the new file name exactly as done also in the first batch file.

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

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

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 or set command line with using a separate command process started in background.

See also single line with multiple commands using Windows batch file for an explanation of the operator &.

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

As long as your files always have the same formatted spaces, you can use a couple For Loops to do most of the work. I am using the approach that you would take the file(s) in question, drag them over and drop them onto the batch file and let 'er rip. Would be able to process roughly 100 files relatively quickly in one go, especially if they are all going to the same final place. I have commented a lot in the batch solution below to help you understand what I am doing (all the "REM" lines)

Using the filename "abcdef - ggggg hhhhhh iiii jj xxxx kkk - pp qq Sep 21, 2021.txt" as the example, we can parse the name via Spaces as the Delimeter. This gives us tokens 12, 13, and 14 needed for our date work needing done, and Token 1, and token 7 for the "abcdef" and "xxxx" data from the filename to create "abcdef_xxxx_09212021.txt"

@Echo Off
setlocal enabledelayedexpansion enableextensions

REM checking to make sure the 1st argument is NOT blank [meaning there is no file dropped onto the tool.]

If "%~1"=="" (
  Echo Please drag and drop the file to parse onto the batch file
  pause
  GOTO :EOF
)
REM Returning from end of script if more than one file are dropped onto tool.
:PostShift


REM Establishing some variables for use later.
REM "%~dp1" becomes the drive and path of arg 1 [the 1st file] which 
REM is "C:\ABC\" [including the final \ in the path]
REM this becomes the final destination - you would need to change
REM this if it is different for each file, or you could specify that 
REM with a prompt of some kind in between the shift cycle.

set "destFolder=DEF"

set "endDir=%~dp1!destFolder!"
REM endDir=C:\ABC\DEF

For /f "Tokens=1,7,12-14 Delims= " %%a in ("%~1") do (
  REM Token 1
  set "term1=%%a"
  REM Token 7
  set "term2=%%b"
  REM Token 12
  set "mth=%%c"
  REM Token 13
  set "day=%%d"
  REM Token 14
  set "yr=%%e"

  set mthCount=0
  REM For loop to determine the proper month.
  For %%M in (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec) do (
    REM increment mthCount up by 1 to start for Jan, then continue up until it sets the proper month
    set /a mthCount+=1
    REM One Liner to confirm the token for the month equals the month in the sequence of the 2nd For Loop
    REM then determines whether mthNumber [to be used in final filename] is defined.  
    REM If it is defined this will fail after being set, and finish out the loop with only the appropriate mth set.

    If "%%M"=="!mth!" if not defined mthNumber set mthNumber=!mthCount!
  )
)

REM Here we will ensure the "MM" format is always in use even w/ single digit months
If !mth! LSS 10 set mth=0!mth!

REM %~x1 provides the same extension as the file being processed so it doesn't have
REM to be specified every time the file changes.
Set "finalFile=!term1!_!term2!_!mth!!day!!yr!%~x1"

REM This If is not necessary, but I saw you include this in your question, 
REM and, for some it gives the nice "warm and fuzzy" feel to KNOW it exists.
If Exist "%~1" (
  Echo I am going to attempt to move this file where you want it to be^^!
  REM Checking if new file already exists
  If Exist "!endDir!\!finalFile!" (
    Echo This file already exists.  Moving in as duplicate.
    Move "%~f1" "!endDir!\DUPLICATE_!finalFile!"
  ) ELSE (
    REM %~f1 is the fully qualified filename for the first file in the mix
    Move "%~f1" "!endDir!\!finalFile!"
  )
)

REM Now we check for other arguments [meaning, other files dropped on the tool at the same time]

If "%~2"=="" (
  Echo No other files have been chosen to be parsed at this time.
  Echo Exiting . . .
  pause
  REM If you have nothing else after this portion of the Batch File, the following
  REM line is NOT needed.
  GOTO :EOF
) ELSE (

  REM Shifts "%2" [2nd file in list] to file one's spot to be parsed 
  REM without having 100's of iterations of code . . . Really, withouth SHIFT,
  REM you could only have 9 repetitions as only 9 arguments are accessible.

  shift /1
  REM Goes back to beginning of file
  GOTO :Postshift 
)


k1dfr0std
  • 379
  • 1
  • 15