Like the question says, I have a folder full of photos but many of the photos are duplicates. The pictures are in groups of 10-15 in the same minute and then the next group has a timestamp of a few minutes later. I want to copy 1 photo from each group to a new folder. I found some code that I think might mostly work, but the command copies and excludes based on file name, not timestamp. Any help would be greatly appreciated.
For %%F In ("G:\Bad\*.*") Do If Not Exist "G:\Good\%%~nxF" Copy "%%F" "C:\Good\%%~nxF"
This file copying task could be done with following batch file:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "LastFileTime="
for %%I in ("C:\Path To\Source Folder\*") do (
if "%%~tI" NEQ "!LastFileTime!" (
set "LastFileTime=%%~tI"
copy /B /Y "%%I" "C:\Path To\Destination Folder\" >nul
)
)
endlocal
Command FOR runs for each non hidden file in specified source folder the IF comparison which compares case-sensitive last modification time of current file with the file time last assigned to environment variable LastFileTime using delayed expansion as required here because the environment variable value is changed and referenced in same command block.
On a difference the last modification file time of current file is assigned to the environment variable and the file is copied to destination folder which must already exist on running this batch file.
Note: On an NTFS drive the list of file names processed by FOR is sorted by file name and not by file time. On a FAT16, FAT32 and ExFAT drive the list of file names is not sorted at all. This means this simple approach works only reliable on an NTFS drive with all files with same last modification date have nearly the same file name.
So it would be better to process the list of files sorted by last modification time for example using following code:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "LastFileTime="
cd /D "C:\Path To\Source Folder"
for /F %%I in ('dir * /A-D /B /OD /TW 2^>nul') do (
if "%%~tI" NEQ "!LastFileTime!" (
set "LastFileTime=%%~tI"
copy /B /Y "%%I" "C:\Path To\Destination Folder\"
)
)
endlocal
DIR outputs all directory entries
matching the wildcard pattern * (*.* is interpreted as * by Windows),
not having attribute directory set because of /A-D which means only the names of files including hidden and system files,
in bare format because of /B which means just file name without any additional information,
with the output list ordered by date/time because of /OD with oldest first and newest last
whereby the date/time to use for sort is the last modification (write) date because of /TW which would not be necessary as the last modification date is the default.
The help output by running dir /? in a command prompt window explains also all these options. And running just dir * and next dir * /A-D /B /OD /TW in a command prompt window in a directory with files and comparing the two output lists makes the difference very clear.
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.
cd /?
copy /?
dir /?
echo /?
endlocal /?
for /?
if /?
set /?
setlocal /?
Read also the Microsoft article about Using Command Redirection Operators to understand >nul used here to suppress the message about number of copied files by redirecting it to device NUL.
2>nul suppresses the error message output by DIR if there is no file in source directory by redirecting the error message output to handle STDERR to device NUL whereby the redirection operator > needs to be escaped here with caret character ^ for being parsed as literal character on parsing the FOR command line by Windows command interpreter and as redirection operator later on execution of DIR command line in a separate command process.
Related
Been trying to create an additional batch script that processes files for me. I either get send 1 or several .pdf test files in a .rar file.
So what I am trying to aim for is:
If the first variable 1 is named 'test' then
Is there a .rar file in the folder from variable 2 then
Extract to a folder and then delete .rar file
else
check that there is a .pdf file and then copy to folder
Else
Tell the user that neither a file or a archive has been found
I've managed to scrape this together but I need help trying to expand it further to include all the options:
#echo off
set "cat=%1"
IF "%cat%"=="test" ( for /f %%G in ('dir *.rar /b') do set filename=%%~G)
echo %filename%
This only gives me half the file name as they have gaps in the filename, also need to change the dir in the 3rd line to be looking in variable 2 that is sent in.
To add to it I've just been told that it's the same for .txt files, the multiples are sent to me in a .rar file
I suggest to open a command prompt, run call /? and read the output help. The help explains how the arguments – also called options or parameters, but not variables – of a batch file can be referenced from within a batch file.
It is advisable to check if a batch file is called with at least one argument if it must be called with at least one argument and output a help for correct usage of the batch file if it was started without any argument or if it was started with /? which is the default on Windows to get help about a command or program.
The manual for console version of WinRAR is the file Rar.txt in program files folder of WinRAR. It can be read in this text file after opening it with a double click that Rar.exe can extract one or more *.rar archive files found in a directory. For that reason it is not really necessary to use command FOR. But it is advisable for this task to use command FOR as the RAR file(s) should be deleted after successful extraction of the RAR archive(s).
Let us look on the FOR command line for /f %%G in ('dir *.rar /b') do and what it does on execution.
FOR with option /F to process a text file content or a single string or the output of a command line results in this case in starting a command process in background with %ComSpec% /c and the command line between the two ' appended. So executed by the Windows command process cmd.exe processing the batch file with for /F is the following with Windows installed into C:\Windows as by default:
C:\Windows\System32\cmd.exe /c dir *.rar /b
The command DIR executed by separate command process in background
searches in current directory
for directory entries (files or directories)
matching the wildcard pattern *.rar
and not having hidden attribute set (implicit default is /A-H on option /A not specified at all)
and outputs to handle STDOUT the found directory entries matching the criteria above in bare format line by line which means with just file/folder name without path and never enclosed in double quotes even on containing a space or one of these characters &()[]{}^=;!'+,`~.
An error message is output by DIR to handle STDERR of background command process if it cannot find any directory entry matching the search criteria.
FOR respectively the command process processing the batch file redirects the output to handle STDERR of the background command process to its own STDERR handle which results in getting it displayed in console window in this case. But the output to handle STDOUT of started background command process is captured by FOR respectively the command process processing the batch file and is processed line by line after started background command process terminated itself.
FOR used with option /F always ignores empty lines. This does not matter here because of DIR does not output empty lines on being executed with option /B.
for /F splits up a non-empty line by default into substrings using normal space and horizontal tab as string delimiters and assigns by default just first space/tab separated string to the specified loop variable which is here the loop variable G. for /F ignores by default additionally also a processed line if the first substring after splitting the line up starts with a semicolon because of eol=; is the default for end of line option.
So the command line for /f %%G in ('dir *.rar /b') do causes several problems on processing the list of directory entries output by DIR.
For a file/folder name containing a space just the first space/tab separated part of the file/folder name is assigned to loop variable G instead of complete name. For example a name like My Archive.rar results in just My is assigned to the loop variable G.
A file/folder name with one or more leading spaces is assigned to loop variable G without those leading spaces which means again that G does not hold complete name. For example a name like TwoLeadingSpaces.rar results in getting assigned to loop variable G just TwoLeadingSpaces.rar without the two leading spaces and the file (or folder) is not found on referencing the value of loop variable G.
A file/folder name with a semicolon at beginning after zero or more leading spaces is completely ignored by command FOR for further processing. For example names like ;Test.rar (name beginning with a semicolon) or ;TestWithALeadingSpace.rar (name with leading space and a semicolon) are completely ignored for further processing by FOR.
The points 2 and 3 are usually no problem as file/folder names with leading space(s) or a semicolon at beginning are really very rare. But a file/folder name with a space occurs very often.
A solution would be using FOR without option /F:
for %%G in (*.rar) do
FOR searches now itself for non-hidden files (not directories) in the current directory matching the wildcard pattern *.rar and assigns a found file name without path to loop variable G and next runs the command(s) after do. There is no additional command process started and there is no substring splitting done.
But there is a problem with this very simple solution in case of the commands executed for each found file name delete, move or rename files matched by the wildcard pattern *.rar. The list of directory entries matching the wildcard pattern changes on each iteration of the body of the FOR loop while command FOR queries the directory entries one after the other with executing the commands between each directory query. This is especially on FAT16, FAT32 and exFAT drives a real problem, but can result also in unexpected behavior on NTFS drives.
Whenever a FOR loop is used to process a list of files which could change during the iterations of the loop because of deleting, moving or renaming the files matched by a wildcard pattern, it is better to process a list of files loaded completely into memory before first iteration of the loop.
So a better solution for this task with the requirement to delete a RAR archive file after successful extraction is:
for /F "eol=| delims=" %%I in ('dir *.rar /A-D /B 2^>nul') do
The DIR option /A-D results in ignoring directory entries with attribute directory. So output by DIR are just file names matching the wildcard pattern in current directory including hidden RAR archive files.
2^>nul is passed as 2>nul to the background command process which results in redirecting the error message output by DIR on no *.rar file found to device NUL to suppress it.
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.
The for /F option eol=| changes the end of line character from ; to |. No file name can have a vertical bar in its file name according to Microsoft documentation about Naming Files, Paths, and Namespaces. So no file name is ignored anymore by FOR because of end of file option.
The for /F option delims= changes the delimiters list for line splitting into substrings to an empty list of delimiters which disables the line splitting behavior completely. So a file name with one or more spaces anywhere in file name is assigned completely to the specified loop variable I.
The task description is not very clear regarding to what to do depending on the batch file arguments, especially if the first argument is not case-insensitive test.
However, the following commented batch file could be working for this task on being called with first argument being test or with no arguments at all or with /? as first argument.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
if "%~1" == "" goto OutputHelp
if "%~1" == "/?" goto OutputHelp
if /I not "%~1" == "test" goto MoreCode
set "SourceFolder=%~2"
if defined SourceFolder goto CheckFolder
echo/
echo Error: Folder with RAR or PDF file(s) not specified on command line.
goto OutputHelp
:CheckFolder
rem Replace all forward slashes by backslashes in folder name.
set "SourceFolder=%SourceFolder:/=\%"
rem Append a backslash to folder path if it does not end with a backslash.
if not "%SourceFolder:~-1%" == "\" set "SourceFolder=%SourceFolder%\"
rem Check the existence of the source folder.
if exist "%SourceFolder%" goto ProcessFolder
echo/
echo Error: Folder "%SourceFolder%" does not exist.
goto OutputHelp
:ProcessFolder
rem Get full qualidfied folder name, i.e. the folder name
rem with its absolute path and ending with a backslash.
for %%I in ("%SourceFolder%") do set "SourceFolder=%%~fI"
rem Define the destination folder for the PDF files extracted from the
rem RAR archive file(s) in source folder or copied from source folder.
set "DestinationFolder=C:\Temp\Test\"
rem Search for all *.rar files in folder passed with second argument and
rem extract all *.pdf files in each RAR archive file to the configured
rem destination folder. Rar.exe creates the destination folder automatically
rem if it is not already existing. The batch file is halted after processing
rem a RAR file on which Rar.exe exited with a value greater 0. Read the exit
rem codes documentation of Rar.exe at bottom of text file Rar.txt for more
rem information about the RAR exit codes. See Rar.txt also for the meaning
rem of the few RAR switches used here.
set "RarFileCount=0"
for /F "eol=| delims=" %%I in ('dir "%SourceFolder%*.rar" /A-D /B 2^>nul') do (
set /A RarFileCount+=1
"%ProgramFiles%\WinRAR\Rar.exe" e -cfg- -idcdp -or -- "%SourceFolder%%%I" *.pdf "%DestinationFolder%"
if not errorlevel 1 (del /A /F "%SourceFolder%%%I") else echo/& pause
)
if %RarFileCount% == 0 goto CheckFiles
if %RarFileCount% == 1 (set "PluralS=") else set "PluralS=s"
echo/
echo Info: Processed %RarFileCount% *.rar file%PluralS% in folder "%SourceFolder%".
goto EndBatch
:CheckFiles
echo Info: There are no *.rar files in folder "%SourceFolder%".
if exist "%SourceFolder%*.pdf" goto CopyFiles
echo Info: There are no *.pdf files in folder "%SourceFolder%".
goto EndBatch
:CopyFiles
rem Copy all PDF files in source folder to destination folder. xcopy.exe
rem creates destination folder automatically if it is not already existing.
echo/
%SystemRoot%\System32\xcopy.exe "%SourceFolder%*.pdf" "%DestinationFolder%" /C /I /Y
goto EndBatch
:OutputHelp
echo/
echo Usage: %~n0 [TEST] [Folder with RAR or PDF file(s)]
echo/
echo If the first argument is case-insensitive TEST, the second argument
echo specifies the folder containing the RAR files to extract or the PDF
echo files to copy to destination folder. The folder must be specified
echo with first argument being TEST.
echo/
pause
goto EndBatch
:MoreCode
rem Add here the code to execute on first argument is not case-insensitive TEST.
:EndBatch
endlocal
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 /?
del /?
dir /?
echo /?
endlocal /?
for /?
goto /?
if /?
pause /?
rem /?
set /?
setlocal /?
xcopy /?
"%ProgramFiles%\WinRAR\Rar.exe" /?
You can use this:
#echo off
set "cat=%~1"
IF "%cat%"=="test" (
for %%G in (*.rar) do set filename=%%G
)
echo %filename%
Here wildcard is used to get all the rar files in the directory.
I want to make a batch or cmd file to automatically select the latest file in the directory D:\Romexis_Bilder\romexis_SQL_Backup. These are ZIP SQL backup files that are generated two times daily in the format yymmddhhmm.zip, e.g Romexis_db201805271200.zip on a server running Windows 2016 Server.
The latest added file to the directory (result of FOR /F) should then be used in SQL RESTORE (backup and ftp program Windows).
The idea was to use the FOR command
My draft:
Go into the directory:
pushd "D:\Romexis_Bilder\romexis_SQL_Backup"
Find the latest file. (I don't really know how to set the parameters here.)
for /f "tokens=*" %% in ('dir /D:\Romexis_Bilder\romexis_SQL_Backup /od') do set newest=%%D:\Romexis_Bilder\romexis_SQL_Backup
The result of FOR should be used in *.zip
cd C:\Program Files (x86)\Pranas.NET\SQLBackupAndFTP\
SqlRestore D:\Romexis_Bilder\romexis_SQL_Backup\*.zip -db Romexis_db -srv .\ROMEXIS -pwd password disconnect Romexis_db
I stuck with FOR, but don't know if there would also be another possibility.
I don't know if the last command line in question is really correct. I have some doubts output this line.
But this code can be used to get the name of the newest *.zip file according to last modification date without path.
#echo off
set "BackupFolder=D:\Romexis_Bilder\romexis_SQL_Backup"
for /F "eol=| delims=" %%I in ('dir "%BackupFolder%\Romexis_db*.zip" /A-D-H /B /O-D /TW 2^>nul') do set "NewestFile=%%I" & goto DatabaseRestore
echo ERROR: Could not find any *.zip backup file in folder:
echo "%BackupFolder%"
echo/
pause
goto :EOF
:DatabaseRestore
cd /D "%ProgramFiles(x86)%\Pranas.NET\SQLBackupAndFTP"
SqlRestore.exe "%BackupFolder%\%NewestFile%" -db Romexis_db -srv .\ROMEXIS -pwd password disconnect Romexis_db
echo/
pause
FOR executes in a separate command process started with cmd.exe /C in background the command line:
dir "D:\Romexis_Bilder\romexis_SQL_Backup\*.zip" /A-D-H /B /O-D /TW 2>nul
DIR outputs to handle STDOUT of background command process
only names of non hidden files because of /A-D-H (attribute not directory and not hidden)
in bare format because of /B just the file name with file extension, but without file path
sorted reverse (newest first) by date because of /O-D
using write time (last modification time) because of /TW
in directory D:\Romexis_Bilder\romexis_SQL_Backup matching the pattern Romexis_db*.zip.
I recommend running this command line in a command prompt window to see at least once what DIR outputs.
DIR would output an error message to handle STDERR in case of no *.zip file found or the directory does not exist at all. This error message is suppressed by redirecting it to device NUL.
Read also 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 the output written to STDOUT and processes the output line by line with ignoring empty lines which do not occur here because of DIR with option /B does not output empty lines.
FOR with option /F would ignore lines starting with a semicolon by default. For that reason end of line character is redefined with eol=| from ; to a vertical bar which file names can't contain. eol=| would not be required in this case because of file name pattern Romexis_dbYYYMMDDhhmm.zip making it unlikely that a file name starts with a semicolon.
FOR with option /F would split up the lines into substrings using space/tab as delimiter and would assign for each line only first space/tab delimited string to specified loop variable I. This line splitting behavior is disabled by specifying an empty list of delimiters with delims=. delims= would not be required in this case because of file name pattern Romexis_dbYYYMMDDhhmm.zip making it unlikely that a file name contains a space character.
The name of the file output first by DIR which is the newest ZIP file in specified directory is assigned to environment variable NewestFile. And next the FOR loop is exited with a jump to label DatabaseRestore as all other file names output by DIR are of no interest for this task.
The command lines below the FOR command line are executed only if there is no *.zip file in specified directory which report this unexpected error case.
It would be also possible to use the DIR command line below in batch file because of file name pattern Romexis_dbYYYMMDDhhmm.zip:
dir "%BackupFolder%\Romexis_db*.zip" /A-D-H /B /O-N 2^>nul
The same command line for execution from within a command prompt window:
dir "D:\Romexis_Bilder\romexis_SQL_Backup\*.zip" /A-D-H /B /O-N 2>nul
The order of the file names in output is here reverse by name which results in printing first the Romexis_db*.zip with newest date/time in file name thanks to date/time format YYYMMDDhhmm.
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.
cd /?
dir /?
echo /?
for /?
goto /?
pause /?
set /?
See also:
Where does GOTO :EOF return to?
Single line with multiple commands using Windows batch file
#Mofi
Thanks you for all your work it helped a lot!
As you advised I used each command in command prompt first to see the outputs (adapted batch %%I to cmd %I and vice versa)
I'm now able to find the newest file in D:\Romexis_Bilder\romexis_SQL_Backup the result is processed an taken as variable into the restore of the database which is done with One-Click SQL Restore https://sqlbackupandftp.com/restore
I did some modification in syntax of your commands O:D since „- „ excludes, removed attribute /TW because it was only listing backups from 2017.
#echo off
set "BackupFolder=D:\Romexis_Bilder\romexis_SQL_Backup"
for /F "eol=| delims=" %I in ('dir "%BackupFolder%\Romexis_db*.zip" /A-D-H /B /O:D 2^>nul') do set "NewestFile=%I" & goto DatabaseRestore
echo ERROR: Could not find any *.zip backup file in folder:
echo "%BackupFolder%"
echo/
pause
goto :EOF
:DatabaseRestore
cd /D "%ProgramFiles(x86)%\Pranas.NET\SQLBackupAndFTP"
SqlRestore.exe "%BackupFolder%\%NewestFile%" -db Romexis_db -srv .\ROMEXIS -pwd password
echo/
pause
Maybe the ^ in 'dir "%BackupFolder%\Romexis_db*.zip" /A-D-H /B /O:D 2^>nul' is not correct in CMD but didn‘t seem affect the result.
It was really advance! Now the GUI of One-Click SQL Restore opens with the newest *zip . The only thing that I still need to get out, is the syntax in command prompt for the restore, now i still need to click on the restore button of the GUI. Or try it over Microsoft Visual Studio SQL or command line tool.
#MOFI no modifications are made to files from 2017 or other files at all, files are not overwritten or modified later, a new file is always created by the back up program 2 times a day with the naming romexis_dbYYYMMDDhhmm.ziptwo times a day. Will try /O-N
THANKS a lot fo you input
I need to delete files in an specific folder with a batch script, however, I need to keep the last file generated. Our server has an IIS folder that keeps generating logs, and we need to keep always the last one, but delete the older ones.
Currently we have this script that deletes all the files in an specific folder (in this case, all the files inside C:\Temp):
del /q "C:\Temp\*"
FOR /D %%p IN ("C:\Temp\*.*") DO rmdir "%%p" /s /q
How could we edit that code to keep the last file generated in the folder?
Thank you in advance for your help.
This batch file offers one solution:
#echo off
set "SourceFolder=C:\Temp"
for /F "skip=1 delims=" %%I in ('dir "%SourceFolder%\*" /A-D /B /O-D 2^>nul') do del "%SourceFolder%\%%I"
set "SourceFolder="
The command DIR outputs a list of just file names because of the options /A-D (directory entries with directory attribute not set) and /B (bare format) ordered reverse by last modification date because of /O-D which means the name of the newest modified file is output first.
An error message output by DIR if the specified folder does not contain any file is suppressed by redirecting the error message written to handle STDERR to device NUL using 2>nul. The redirection operator > must be escaped here with caret character ^ to be interpreted as literal character on processing the entire FOR command line by Windows command interpreter. Later FOR executes in a separate command process in background the command dir "%SourceFolder%\*" /A-D /B /O-D 2>nul and captures the output written to STDOUT.
FOR option skip=1 results in skipping first line of captured output which means ignoring the file name of newest modified file.
FOR option delims= disables the default splitting up of the captured lines into space/tab separated strings as every entire file name should be assigned to loop variable I for usage by command executed by FOR.
DEL deletes the file if that is possible at all.
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.
del /?
dir /?
echo /?
for /?
set /?
Read also the Microsoft article about Using Command Redirection Operators.
I created the following batch script to create a folder based on today's date and then group files into folders based on the file name.
For example the files
JIM_BRICKMAN_QPS.avi
JIM_BRICKMAN_Slice.avi
JIM_BRICKMAN_Slice.jpg
are moved to the folder BRICKMAN.
This works fine, however, attempts to modify the batch file to move the newly created folders into the newly created date folder fail or overwrite the folders when going through the loop.
for /F "tokens=1-4 delims=/" %%A in ('date /t') do (
set DateDay=%%A
set DateMonth=%%B
set DateYear=%%C
)
set CurrentDate=%DateDay%-%DateMonth%-%DateYear%
if not exist "%CurrentDate%" md %CurrentDate%
for %%A in (*.avi *.jpg) do (
for /f "tokens=1,* delims=_" %%D in ("%%~nA") do (
md "%%D" 2>nul
echo Moving file %%A to folder %%D
move "%%A" "%%D" >nul
)
)
echo Finished
Additionally, I can't seem to get the token to ignore the first delimiter so that the folder is titled JIM_BRICKMAN and not just BRICKMAN.
EDIT:
I rewrote the batch file after the suggestions in the comments:
set "CurrentDate=%DATE:~-10,2%-%DATE:~-7,2%-%DATE:~-4%"
if not exist "%CurrentDate%" md %CurrentDate%
for %%A in (*.avi *.jpg) do (
for /f "tokens=1,2 delims=_" %%D_%%E in ("%%~nA") do (
md "%%D_%%E" 2>nul
move "%%A" "%%D_%%E" >nul
)
)
But the script seems to bomb out. I tried to capture the error, but it closes despite me putting PAUSE in the script.
Double clicking on a batch file in development is no good idea because this results in starting
%SystemRoot%\System32\cmd.exe /c "batch file name with full path and extension"
As it can be read on running cmd /? from within a command prompt window, the option /C means close the command process and its console window immediately after execution of command, executable or script finished independent on the reason for ending the execution.
For debugging a batch file in development it is much better to
open a command prompt window,
change the current directory with command CD to directory of batch file and
run the batch file by typing its name and hitting key RETURN or ENTER.
For batch files which should work independent on which directory is the current directory, it is advisable to omit point 2 and run the batch file with entering its full path, file name and file extension enclosed in double quotes with current directory being not the directory of the batch file.
A batch file is executed from within a command prompt window with:
%SystemRoot%\System32\cmd.exe /K BatchFileNameAsTyped
The option /K means keep command process running which results in keeping also command prompt window opened after execution of command/executable/script which makes it possible to read error messages.
The keys UP ARROW and DOWN ARROW can be used to reload command lines once entered in command prompt window making it easy to run the batch file once again after making a modification in GUI text editor.
And with having #echo off removed from first line of batch file, or changed to #echo ON, or commented out this line with command REM or with :: (invalid label) at beginning, it is also possible to see which lines Windows command interpreter really executes after applying immediate environment variable expansion and where an error occurs in case of a syntax error.
Wrong on second batch code is the line:
for /f "tokens=1,2 delims=_" %%D_%%E in ("%%~nA") do (
Specified as loop variable must be always 1 character. Right would be:
for /f "tokens=1,2 delims=_" %%D in ("%%~nA") do (
The command echo %DATE% outputs on my computer with my account and my region settings today the date 01.04.2017.
The command echo %DATE:~-10,2%-%DATE:~-7,2%-%DATE:~-4% outputs 01-04-2017.
So this part of the script works.
Hint: A list of directories in format YYYY-MM-DD is better than in format DD-MM-YYYY. The list of directories with format YYYY-MM-DD sorted alphabetically as by default is automatically with this date format also sorted from oldest to newest. Date format DD-MM-YYYY results in a weird list of the directories on being sorted alphabetically as by default.
A batch file for this task could be:
#echo off
set "CurrentDate=%DATE:~-10,2%-%DATE:~-7,2%-%DATE:~-4%"
for %%A in (*.avi *.jpg) do (
for /F "tokens=1,2 delims=_" %%D in ("%%~nA") do (
if not "%%E" == "" (
md "%CurrentDate%\%%D_%%E" 2>nul
move /Y "%%A" "%CurrentDate%\%%D_%%E\"
) else (
md "%CurrentDate%\%%D" 2>nul
move /Y "%%A" "%CurrentDate%\%%D\"
)
)
)
set "CurrentDate="
How the inner loop works is most interesting for this task.
for /F and "%%~nA" means the command FOR should process just the file name of the *.avi or *.jpg file without file extension found by outer FOR loop.
delims=_ means the FOR command should split up the string into multiple parts (tokens) using underscore as delimiter. The first file name is JIM_BRICKMAN_QPS which would be split up to:
JIM assigned to loop variable D being specified in FOR command line,
BRICKMAN assigned to loop variable E which is the next character in ASCII table after D and
QPS assigned to loop variable F.
This string split feature is the reason why loop variables are interpreted case-sensitive while environment variables are interpreted not case-sensitive.
With tokens=1,2 is specified that just first and second string parts are of interest. So inner FOR can stop string splitting after having already determined the first two underscore delimited strings and having assigned them to the loop variables D and E.
FOR executes the command block if it could determine at least 1 string delimited by an underscore. So it is possible that loop variable D has a string value, but loop variable E is an empty string, for example if the file name does not contain any underscore. That is the reason for the IF condition.
The command MD creates with command extensions enabled as by default the entire directory tree. Therefore it is not necessary to create the date subdirectory explicitly before searching for *.avi and *.jpg files. That is good as it avoids creating empty date directories when there are no *.avi and *.jpg files in current directory.
As the *.avi and *.jpg files in current directory should be moved to DD-MM-YYYY\Token1_Token2 it is of course necessary to specify also the environment variable with todays date string on creating the directory and moving the file.
The error message output by MD if the directory exists (or when it fails to create the directory because of missing permissions) to handle STDERR is redirected with 2>nul to device NUL to suppress it.
The MOVE command is used with option /Y to move the file to target folder even if the current file exists already in target folder.
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.
echo /?
for /?
if /?
md /?
move /?
set /?
Read also the Microsoft article about Using Command Redirection Operators.
I am in the need of a batch script that checks a drive (D:) for the 'last modified' attribute of *.czi files (Carl Zeiss image files) and append the data to a file on another drive. I have tried solutions with the following line:
FOR /F "delims=" %%I IN ('DIR %source%*.czi /A:-D /O:-D /T:W /B') DO COPY "%%I" > %target%
that does give me the last file, but it copies the entire file which is not that smart since they can be big. As a biologist I will spare you for my desperate attempts that did not work (spent 4-5 hours). I figure this can be done dead easily, that is if you know how... Any good suggestions? Any reply will be appreciated! Thanks in advance.
Let's assume just the last modified file time from newest file is wanted from all *.czi files in directory C:\Temp containing for example:
30.01.2017 08:13 First Listed.czi
28.01.2017 21:26 Oldest Image.czi
03.02.2017 17:13 Newest Image.czi
The batch code for this task could be:
#echo off
set "Source=C:\Temp\"
set "Target=%Source%List.txt"
for /F "delims=" %%I in ('dir "%Source%*.czi" /A:-D /B /O:-D /T:W 2^>nul') do (
echo File "%%I" last modified on %%~tI>>"%Target%"
goto AfterLoop
)
:AfterLoop
The command DIR searches in for *.czi files in directory C:\Temp and outputs the list sorted by last modification time in reverse order from newest to oldest.
In case of no *.czi file could be found, command DIR would output an error message to handle STDERR. This output message is redirected with 2>nul to device NUL to suppress it whereby the redirection operator > must be escaped here with ^ to be interpreted as redirection operator on execution of DIR command line and not already on parsing FOR command line.
%%I references the name of the file as output by DIR and %%~tI references the last modification date of the file. The help of command FOR output by running in a command prompt window for /? explains those modifiers.
The loop is exited after first output of the text redirected to the target file on which the line is appended if it is already existing because of using >> instead of just >.
For the example files list the following line is appended to C:\Temp\List.txt:
File "Newest Image.czi" last modified on 03.02.2017 17:13
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 /?
for /?
goto /?
set /?
See also the Microsoft article Using command redirection operators.
Your question is unclear, so let me try to rephrase it:
I think you want to find the Most Recently Modified file with a .CZI extension, and copy only that newest file to some target destination.
To list all .CZI files in all subdirectories, sorted by newest-file first:
(for /f %a in ('dir *.CZI /s /b') do #echo %~ta %~fa) | sort
If the first line of this output is the file that you want, then all you need to do is copy that one file to your target.
(and please, take the time to write detailed and clear questions so we can provide good answers)