jardane
jardane

Reputation: 471

make batch file that creates a folder with today's date then moves files from a folder in to that newly created folder

I need to make a batch file that will make a folder with today's date in month day year format (example 080112). Then once it's created i need to move files from a set folder in to the folder it just created. To be honest i don't know how to make a batch file.

Upvotes: 4

Views: 21817

Answers (7)

Mofi
Mofi

Reputation: 49086

It is advisable not using the dynamic variable DATE of the Windows Command Processor cmd.exe or its internal command date executed with option /T to output just the current date using one more cmd.exe started in background to get the current date in the wanted format MMddyyyy because of these solutions depend on which country/region is configured for the account used on running the batch file.

There are lots of different date formats as documented on the Wikipedia page date format by country.

Usage of ROBOCOPY to get current date and move the files

A solution to get current date region independent is using ROBOCOPY which is available since Windows Vista and Windows Server 2003 in system directory of Windows, but is by default not available on Windows XP. robocopy.exe of Windows Server 2003 can be copied to %SystemRoot%\System32 of Windows XP to use this executable also on Windows XP, but it is not available by default on Windows XP.

ROBOCOPY is executed with invalid source directory string "C:\|" and valid destination directory string . (could be also something other valid) and argument /NJH to suppress the output of the header information.

robocopy "C:\|" . /NJH

This execution produces the error message:


2022/07/10 10:34:23 ERROR 123 (0x0000007B) Accessing Source Directory C:\|\
The filename, directory name, or volume label syntax is incorrect.

The format of current date/time at beginning of second line after the empty line is region independent.

This output can be used to get current date in wanted format to move the files into a directory with the current date in format MMddyyyy in name.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "tokens=1-3 delims=/ " %%G in ('%SystemRoot%\System32\robocopy.exe "%SystemDrive%\|" . /NJH') do %SystemRoot%\System32\robocopy.exe "C:\Source Directory" "C:\Destination Directory\%%H%%I%%G" /MOV /NDL /NFL /NJH /NJS /R:3 /W:2 & goto FileMovesDone
:FileMovesDone
endlocal

FOR starts in this case one more command process in background with %ComSpec% /c and the command line between the two ' appended as additional arguments which results in Windows being installed into C:\Windows in the execution of:

C:\Windows\System32\cmd.exe /c C:\Windows\System32\robocopy.exe "C:\|" . /NJH

The first three slash or space separated strings of the first non-empty line of the error message output to handle STDOUT of the background command process captured by FOR are assigned to:

  • G ... year
  • H ... month
  • I ... day

The three data strings are concatenated to the date string in the wanted format in the destination directory argument string of the ROBOCOPY command executed next to move all files in the specified source directory C:\Source Directory into the destination directory. ROBOCOPY automatically creates the entire directory tree to the destination directory.

But FOR would run the command SET once again for the second error message line. For that reason the unconditional operator & is used to run independent on success or failure of files movement by ROBOCOPY the command GOTO to continue batch file processing on the line below the label FileMovesDone and so exiting the FOR loop before processing the second non-empty line of the error message of ROBOCOPY.

Better would be using this code:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "tokens=1-3 delims=/ " %%G in ('%SystemRoot%\System32\robocopy.exe "%SystemDrive%\|" . /NJH') do %SystemRoot%\System32\robocopy.exe "C:\Source Directory" "C:\Destination Directory\%%G-%%H-%%I" /MOV /NDL /NFL /NJH /NJS /R:3 /W:2 & goto FileMovesDone
:FileMovesDone
endlocal

The difference is using %%G-%%H-%%I instead of %%H%%I%%G resulting in creation of the destination directory with name in international date format yyyy-MM-dd. That date format is easier to read and has additionally the advantage that the directories listed ordered by name are listed at the same time also in correct chronological order.


Usage of WMIC to get current date region independent

A different solution is required to get the current date region independent for Windows XP because of ROBOCOPY is not available by default on Windows XP.

A region independent date/time string can be get using Windows Management Instrumentation Command line tool WMIC.

The command line

wmic OS GET LocalDateTime /VALUE

outputs UTF-16 Little Endian encoded for example:



LocalDateTime=20220710105636.581000+120


There are two empty lines, then the line with the current local date/time in format yyyyMMddHHmmss.microsecond±UTC offset in minutes and two more empty lines.

The data can be used with a batch code like this:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "FolderDate=%%I"
set "DestinationFolder=C:\Destination Directory\%FolderDate:~4,2%%FolderDate:~6,2%%FolderDate:~0,4%"
md "%DestinationFolder%"
if exist "%DestinationFolder%\" move /Y "C:\Source Directory\*" "%DestinationFolder%\"
endlocal

Of interest is here only the date/time string between the equal sign and the decimal point which is the reason for using for /F options tokens=2 delims==. to get just 20220710105636 assigned to loop variable I of which value is assigned next to environment variable FolderDate.

The environment variable FolderDate is reformatted using string substitutions to get the date string in format MMddyyy resulting in environment variable DestinationFolder being defined with C:\Destination Directory\07102020.

The advantage of using WMIC to get local date/time is its independence on Windows region settings and that it is working even on Windows XP. The disadvantage is that the command execution takes a quite long time (one to two seconds on Windows XP, more than 50 ms on Windows Vista a newer Windows versions) in comparison to the usage of the dynamic DATE variable which is accessed in a few microseconds.

The command FOR has problems parsing UTF-16 LE encoded Unicode output correct. It interprets the byte sequence 0D 00 0A 00 (carriage return + line-feed) of the WMIC output wrong as 0D 0D 0A, i.e. as two carriage returns and one line-feed. This results in interpreting the last two empty lines at end of WMIC output as two lines with a single carriage return as string.

That is very often a problem because the result of set "EnvironmentVariable=%%I" is with %%I expanding to just carriage return the deletion of the environment variable already defined before with the correct value.

There are multiple solutions to work around this Unicode parsing error of command FOR. It is possible to append & goto Label to exit the loop with a jump to :Label below the FOR loop once the value is assigned to the environment variable to avoid running into this problem at all.

Another solution is using if not defined FolderDate set "FolderDate=%%I" with set "FolderDate=" above the FOR command line to make sure the command SET is executed only once.

One more solution is the one used in this code. The name of the property and its value are output on same line because of using WMIC option /VALUE. The command FOR runs the command SET because of tokens=2 only when it could split up the current line into at least two substrings (tokens) using equal sign and dot as delimiters because of delims==.. But the wrong parsed empty lines of WMIC output is for FOR just a line containing only a carriage return and therefore has no second token. For that reason the wrongly parsed empty lines are also ignored here by the command FOR.

See How to correct variable overwriting misbehavior when parsing output? and cmd is somehow writing Chinese text as output for details on parsing problem of FOR on UTF-16 Little Endian encoded output.

This solution with international date format yyyy-MM-dd:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "FolderDate=%%I"
set "DestinationFolder=C:\Destination Directory\%FolderDate:~0,4%-%FolderDate:~4,2%-%FolderDate:~6,2%"
echo md "%DestinationFolder%"
if exist "%DestinationFolder%\" move /Y "C:\Source Directory\*" "%DestinationFolder%\"
endlocal

The fourth line is different to create the destination folder name with 2022-07-10 instead of 07102022.


What is wrong with the other solutions?

Answer written by Erik Eidt

The command line reformats the value of the dynamic variable DATE by using the command line:

set TODAY=%date:~10,4%%date:~7,2%%date:~4,2%

The environment variable TODAY is defined with 027. on my Windows PC with German (Austria) configured for my user account and not with 20220710 (yyyyMMdd) as the command line is most likely designed for or with 07102022 (MMddyyyy) as it is asked for. The reason is that echo %DATE% outputs on my PC the date string 10.07.2022 (dd.MM.yyyy) and not Sun 10/07/2022 (ddd dd/MM/yyyy with ddd representing abbreviated weekday) and for that reason the three string substitutions in the command line do not work for the date string on my Windows PC with my user account.

A better solution using dynamic variable DATE would be:

set "TODAY=%DATE:~-7,2%%DATE:~-10,2%%DATE:~-4%"

This solution gets the date in format MMddyyyy or ddMMyyyy independent on date string having the weekday at the beginning or is without weekday which is also a difference between the various countries/regions. The remaining problem is that the region dependent date can be either with first month, second day and third year or as in my case first day, second month and third year.

So the command line for MM/dd/yyyy (United States date format) must be:

set "TODAY=%DATE:~-10,2%%DATE:~-7,2%%DATE:~-4%"

That would define the environment variable TODAY with the string 07102022 for the date string 07/10/2022 (without weekday) as well as the date string Sun 07/10/2022 (with weekday).

For more details about the string substitutions see:
What does %date:~-4,4%%date:~-10,2%%date:~-7,2%_%time:~0,2%%time:~3,2% mean?

Answer written by Jony Adamit

This is the worst solution because of the internal command date of cmd.exe executed with option /T outputs always the same date string as echo %DATE%, i.e. the output string is the same string as of dynamic variable DATE which can be accessed directly as shown above.

It does not make sense to use three for /F to start three times in background one more cmd.exe with option /c and the command line date /T to let the background command process output the current date to its handle STDOUT, capture that output with cmd.exe processing the batch file, split up the date string into three substrings (tokens) and use always just one of the three substrings. This is really a waste of CPU power and CPU time and cause also unnecessary file system accesses.

That very inefficient solution works additionally only for a date string in format ddd MM/dd/yyyy with a weekday at beginning like for the United States date format. It does not work for dates without a weekday or using a different separator than / like . and the order of day and month in date string could be different depending on which country/region is configured for the used account.

Answer written by mangyan

This solution uses also the inefficient approach to start in background one more cmd.exe to process the date string which could be done also with using the following command line without using one more cmd.exe:

FOR /f "tokens=2-4 delims=/ " %%i in ("%DATE%") do SET today_fname=%%i%%j%%k

However, this solution works also only for date strings in format ddd MM/dd/yyyy with a weekday at beginning. So it is also not really good and not really efficient.

Answer written by Anna Malai

There is written in the comment that the commands date /t and time /t are used to get current date and time although in real the code uses the dynamic variables DATE and TIME.

The environment variable TIMESTAMP is defined not only with the date in format MMddyyyy as it is asked for, but also with time and it looks like the wanted format is yyyy-MM-dd-HH-mm-ss which of course works only for a date and time in format ddd MM/dd/yyyy HH:mm:ss

The command line md e:\example\"%1\%TIMESTAMP%" to create the directory is of not correct syntax because of " inside the directory path instead of surrounding the entire directory path. That wrong syntax is corrected automatically by cmd.exe because of " is an invalid character in a file/folder name. So cmd.exe removes " from the directory string before passing it to the Windows file I/O functions. It is also unclear why %1 is inside the path which references the first argument of the batch file.

jardane asked for creation of a folder with current date in format MMddyyyy to move files into it. So why the command XCOPY is used in the answer for copying instead of moving files is unclear. The destination path is different to the directory created before with command MD. The option /e of XCOPY is used to copy entire Windows directory with nearly all files (hidden and system files are ignored) in all subdirectories with copying also empty subdirectories to the specified destination directory. The command XCOPY creates automatically also the destination folder on copying multiple files and the user answers the prompt if E:\windows\%TIMESTAMP% specifies a file name or a directory with pressing the key for directory. (The prompt can be avoided by ending the destination folder path with a backslash.)

The last command line with @echo on makes no sense on first line enabling already explicitly the command echo mode.

Answer written by hoggar

That answer demonstrates that the three string substitutions applied on value of dynamic variable DATE can be used also directly on a command line. The command SET is not really necessary. But the code does not create the directory at all because of MOVE does not create automatically the destination directory like ROBOCOPY. The date string value of dynamic variable DATE must be in format ddd dd/MM/yyyy to get really the folder name with date in format MMddyyyy.


Additional information

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.

  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • md /?
  • move /?
  • robocopy /?
  • set /?
  • setlocal /?
  • wmic /?
  • wmic os /?
  • wmic os get /?
  • wmic os get localdatetime /?

PS: There are lots of other solutions to get current date/time in a specific format independent on country configured for the used account. All those alternative solutions can be found in the answers on:

How do I get current date/time on the Windows command line in a suitable format for usage in a file/folder name?

Upvotes: 0

mangyan
mangyan

Reputation: 26

FOR /f "tokens=2-4 delims=/ " %%i in ('DATE/T') do SET today_fname=%%i%%j%%k
md c:\myfolder\%today_fname%
REM This creates a folder named 05242016 in c:\myfolder

Upvotes: 1

hoggar
hoggar

Reputation: 3817

Just rename the folder with Erik's suggestion:

move FolderName FolderName_%date:~7,2%%date:~4,2%%date:~10,4%

Upvotes: 0

Anna Malai
Anna Malai

Reputation: 9

@echo on

:: Use date /t and time /t from the command line to get the format of your date and
:: time; change the substring below as needed.

:: This will create a timestamp like yyyy-mm-dd-hh-mm-ss.
set TIMESTAMP=%DATE:~10,4%-%DATE:~4,2%-%DATE:~7,2%-%TIME:~0,2%-%TIME:~3,2%-%TIME:~6,2%

@echo TIMESTAMP=%TIMESTAMP%

:: Create a new directory
md e:\example\"%1\%TIMESTAMP%"
xcopy /y c:\windows E:\windows\%TIMESTAMP% /e

@echo on

Upvotes: 0

Enterprise User
Enterprise User

Reputation: 3

Was having trouble with this one myself, but directions without further ado: Put your source folder here after the .bat file:

yourscript.bat c:\users\myname\Desktop\sourcefolder

Hope that helps someone else, took me a few seconds :D

Upvotes: -1

Erik Eidt
Erik Eidt

Reputation: 26646

set TODAY=%date:~10,4%%date:~7,2%%date:~4,2%

is an alternative way to get the date part into a shell variable

from: http://stevesgeekspeak.com/2010/01/howto-get-variable-substrings-in-batcmd-scripts/

Jony ... FTW, of course, for having the whole answer.

Upvotes: 4

Jony Adamit
Jony Adamit

Reputation: 3416

This will show you how to set the date in variables.

The rest is just using copy/xcopy to that folder :)

Tell me if you need more elaboration on how to do it.

Cheers!

[EDIT]: Here is the complete solution:

Create a file using notepad -> save as "something.bat" OR using CMD -> copy con something.bat (and once you're done press Ctrl-Z) And paste the following code:

@echo off
IF "%1"=="" GOTO MissingArgument
for /f "tokens=2-4 delims=/ " %%a in ('date /T') do set year=%%c
for /f "tokens=2-4 delims=/ " %%a in ('date /T') do set month=%%a
for /f "tokens=2-4 delims=/ " %%a in ('date /T') do set day=%%b
set TODAY=%month%%day%%year%
md %TODAY%
MOVE %1\*.* %TODAY%
GOTO end
:MissingArgument
echo Incorrect Syntax: Source Folder Name Required!
:end

Hope this helps!

Upvotes: 4

Related Questions